mirror of
https://github.com/reactos/reactos.git
synced 2025-07-26 23:14:17 +00:00
[RSHELL]
* Overhaul the Popup method's position calculation. It now takes into account proper alignment preferences and exclusion rectangles in order to position menu popups better. * Fix a small compatibility issue with windows shell objects. * Use the item rectangle for the exclusion, so that the popup code can properly calculate how to flip the menu position if it doesn't fit downwards. [EXPLORER] * Fix the flags sent to Popup when showing the start menu. We have flags that say exactly what we want, and MPPF_ALIGN_LEFT/RIGHT were introduced with NT6 anyhow. CORE-9004 #resolve #comment Should be fixed with trunk r66030. svn path=/trunk/; revision=66030
This commit is contained in:
parent
12d6b50f62
commit
ad29cd12e8
4 changed files with 166 additions and 47 deletions
|
@ -1972,18 +1972,22 @@ ChangePos:
|
||||||
case ABE_BOTTOM:
|
case ABE_BOTTOM:
|
||||||
pt.x = rcExclude.left;
|
pt.x = rcExclude.left;
|
||||||
pt.y = rcExclude.top;
|
pt.y = rcExclude.top;
|
||||||
dwFlags |= MPPF_BOTTOM;
|
dwFlags |= MPPF_TOP;
|
||||||
break;
|
break;
|
||||||
case ABE_TOP:
|
case ABE_TOP:
|
||||||
case ABE_LEFT:
|
|
||||||
pt.x = rcExclude.left;
|
pt.x = rcExclude.left;
|
||||||
pt.y = rcExclude.bottom;
|
pt.y = rcExclude.bottom;
|
||||||
dwFlags |= MPPF_TOP | MPPF_ALIGN_RIGHT;
|
dwFlags |= MPPF_BOTTOM;
|
||||||
|
break;
|
||||||
|
case ABE_LEFT:
|
||||||
|
pt.x = rcExclude.right;
|
||||||
|
pt.y = rcExclude.top;
|
||||||
|
dwFlags |= MPPF_RIGHT;
|
||||||
break;
|
break;
|
||||||
case ABE_RIGHT:
|
case ABE_RIGHT:
|
||||||
pt.x = rcExclude.right;
|
pt.x = rcExclude.left;
|
||||||
pt.y = rcExclude.bottom;
|
pt.y = rcExclude.top;
|
||||||
dwFlags |= MPPF_TOP | MPPF_ALIGN_LEFT;
|
dwFlags |= MPPF_LEFT;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -268,6 +268,37 @@ HRESULT STDMETHODCALLTYPE CMenuDeskBar::GetSite(REFIID riid, void **ppvSite)
|
||||||
return m_Site->QueryInterface(riid, ppvSite);
|
return m_Site->QueryInterface(riid, ppvSite);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void AdjustForExcludeArea(BOOL alignLeft, BOOL alignTop, BOOL preferVertical, PINT px, PINT py, INT cx, INT cy, RECTL rcExclude) {
|
||||||
|
RECT rcWindow = { *px, *py, *px + cx, *py + cy };
|
||||||
|
|
||||||
|
if (rcWindow.right > rcExclude.left && rcWindow.left < rcExclude.right &&
|
||||||
|
rcWindow.bottom > rcExclude.top && rcWindow.top < rcExclude.bottom)
|
||||||
|
{
|
||||||
|
if (preferVertical)
|
||||||
|
{
|
||||||
|
if (alignTop && rcWindow.bottom > rcExclude.top)
|
||||||
|
*py = rcExclude.top - cy;
|
||||||
|
else if (!alignTop && rcWindow.top < rcExclude.bottom)
|
||||||
|
*py = rcExclude.bottom;
|
||||||
|
else if (alignLeft && rcWindow.right > rcExclude.left)
|
||||||
|
*px = rcExclude.left - cx;
|
||||||
|
else if (!alignLeft && rcWindow.left < rcExclude.right)
|
||||||
|
*px = rcExclude.right;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (alignLeft && rcWindow.right > rcExclude.left)
|
||||||
|
*px = rcExclude.left - cx;
|
||||||
|
else if (!alignLeft && rcWindow.left < rcExclude.right)
|
||||||
|
*px = rcExclude.right;
|
||||||
|
else if (alignTop && rcWindow.bottom > rcExclude.top)
|
||||||
|
*py = rcExclude.top - cy;
|
||||||
|
else if (!alignTop && rcWindow.top < rcExclude.bottom)
|
||||||
|
*py = rcExclude.bottom;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
HRESULT STDMETHODCALLTYPE CMenuDeskBar::Popup(POINTL *ppt, RECTL *prcExclude, MP_POPUPFLAGS dwFlags)
|
HRESULT STDMETHODCALLTYPE CMenuDeskBar::Popup(POINTL *ppt, RECTL *prcExclude, MP_POPUPFLAGS dwFlags)
|
||||||
{
|
{
|
||||||
HRESULT hr;
|
HRESULT hr;
|
||||||
|
@ -321,59 +352,143 @@ HRESULT STDMETHODCALLTYPE CMenuDeskBar::Popup(POINTL *ppt, RECTL *prcExclude, MP
|
||||||
|
|
||||||
RECT rcWorkArea;
|
RECT rcWorkArea;
|
||||||
GetWindowRect(GetDesktopWindow(), &rcWorkArea);
|
GetWindowRect(GetDesktopWindow(), &rcWorkArea);
|
||||||
int waHeight = rcWorkArea.bottom - rcWorkArea.top;
|
int cxWorkArea = rcWorkArea.right - rcWorkArea.left;
|
||||||
|
int cyWorkArea = rcWorkArea.bottom - rcWorkArea.top;
|
||||||
|
|
||||||
int x = ppt->x;
|
int x = ppt->x;
|
||||||
int y = ppt->y;
|
int y = ppt->y;
|
||||||
int cx = rc.right - rc.left;
|
int cx = rc.right - rc.left;
|
||||||
int cy = rc.bottom - rc.top;
|
int cy = rc.bottom - rc.top;
|
||||||
|
|
||||||
switch (dwFlags & 0xFF000000)
|
// TODO: Make alignLeft default to TRUE in LTR systems or whenever necessary.
|
||||||
|
BOOL alignLeft = FALSE;
|
||||||
|
BOOL alignTop = FALSE;
|
||||||
|
BOOL preferVertical = FALSE;
|
||||||
|
switch (dwFlags & MPPF_POS_MASK)
|
||||||
{
|
{
|
||||||
|
case MPPF_TOP:
|
||||||
|
alignTop = TRUE;
|
||||||
|
preferVertical = TRUE;
|
||||||
|
break;
|
||||||
|
case MPPF_LEFT:
|
||||||
|
alignLeft = TRUE;
|
||||||
|
break;
|
||||||
case MPPF_BOTTOM:
|
case MPPF_BOTTOM:
|
||||||
x = ppt->x;
|
alignTop = FALSE;
|
||||||
y = ppt->y - rc.bottom;
|
preferVertical = TRUE;
|
||||||
break;
|
break;
|
||||||
case MPPF_RIGHT:
|
case MPPF_RIGHT:
|
||||||
x = ppt->x + rc.left;
|
alignLeft = FALSE;
|
||||||
y = ppt->y + rc.top;
|
|
||||||
break;
|
|
||||||
case MPPF_TOP | MPPF_ALIGN_LEFT:
|
|
||||||
x = ppt->x - rc.right;
|
|
||||||
y = ppt->y + rc.top;
|
|
||||||
break;
|
|
||||||
case MPPF_TOP | MPPF_ALIGN_RIGHT:
|
|
||||||
x = ppt->x;
|
|
||||||
y = ppt->y + rc.top;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Try the selected alignment and verify that it doesn't escape the work area.
|
||||||
|
if (alignLeft)
|
||||||
|
{
|
||||||
|
x = ppt->x - cx;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
x = ppt->x;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (alignTop)
|
||||||
|
{
|
||||||
|
y = ppt->y - cy;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
y = ppt->y;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (prcExclude)
|
||||||
|
AdjustForExcludeArea(alignLeft, alignTop, preferVertical, &x, &y, cx, cy, *prcExclude);
|
||||||
|
|
||||||
|
// Verify that it doesn't escape the work area, and flip.
|
||||||
|
if (alignLeft)
|
||||||
|
{
|
||||||
|
if (x < rcWorkArea.left && (ppt->x+cx) <= rcWorkArea.right)
|
||||||
|
{
|
||||||
|
alignLeft = FALSE;
|
||||||
|
if (prcExclude)
|
||||||
|
x = prcExclude->right - ((x + cx) - prcExclude->left);
|
||||||
|
else
|
||||||
|
x = ppt->x;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if ((ppt->x + cx) > rcWorkArea.right && x >= rcWorkArea.left)
|
||||||
|
{
|
||||||
|
alignLeft = TRUE;
|
||||||
|
if (prcExclude)
|
||||||
|
x = prcExclude->left - cx + (prcExclude->right - x);
|
||||||
|
else
|
||||||
|
x = ppt->x - cx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL flipV = FALSE;
|
||||||
|
if (alignTop)
|
||||||
|
{
|
||||||
|
if (y < rcWorkArea.top && (ppt->y + cy) <= rcWorkArea.bottom)
|
||||||
|
{
|
||||||
|
alignTop = FALSE;
|
||||||
|
if (prcExclude)
|
||||||
|
y = prcExclude->bottom - ((y + cy) - prcExclude->top);
|
||||||
|
else
|
||||||
|
y = ppt->y;
|
||||||
|
|
||||||
|
flipV = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if ((ppt->y + cy) > rcWorkArea.bottom && y >= rcWorkArea.top)
|
||||||
|
{
|
||||||
|
alignTop = TRUE;
|
||||||
|
if (prcExclude)
|
||||||
|
y = prcExclude->top - cy + (prcExclude->bottom - y);
|
||||||
|
else
|
||||||
|
y = ppt->y - cy;
|
||||||
|
|
||||||
|
flipV = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (prcExclude)
|
||||||
|
AdjustForExcludeArea(alignLeft, alignTop, preferVertical, &x, &y, cx, cy, *prcExclude);
|
||||||
|
|
||||||
|
if (x < rcWorkArea.left)
|
||||||
|
x = rcWorkArea.left;
|
||||||
|
|
||||||
|
if (cx > cxWorkArea)
|
||||||
|
cx = cxWorkArea;
|
||||||
|
|
||||||
if (x + cx > rcWorkArea.right)
|
if (x + cx > rcWorkArea.right)
|
||||||
{
|
x = rcWorkArea.right - cx;
|
||||||
// FIXME: Works, but it's oversimplified.
|
|
||||||
x = prcExclude->left - cx;
|
|
||||||
dwFlags = (dwFlags & (~MPPF_TOP)) | MPPF_LEFT;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (y < rcWorkArea.top)
|
if (y < rcWorkArea.top)
|
||||||
{
|
|
||||||
y = rcWorkArea.top;
|
y = rcWorkArea.top;
|
||||||
}
|
|
||||||
|
|
||||||
if (cy > waHeight)
|
if (cy > cyWorkArea)
|
||||||
{
|
cy = cyWorkArea;
|
||||||
cy = waHeight;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (y + cy > rcWorkArea.bottom)
|
if (y + cy > rcWorkArea.bottom)
|
||||||
{
|
|
||||||
y = rcWorkArea.bottom - cy;
|
y = rcWorkArea.bottom - cy;
|
||||||
}
|
|
||||||
|
|
||||||
int flags = SWP_SHOWWINDOW | SWP_NOACTIVATE;
|
int flags = SWP_SHOWWINDOW | SWP_NOACTIVATE;
|
||||||
|
|
||||||
this->SetWindowPos(HWND_TOPMOST, x, y, cx, cy, flags);
|
this->SetWindowPos(HWND_TOPMOST, x, y, cx, cy, flags);
|
||||||
|
|
||||||
|
if (flipV)
|
||||||
|
{
|
||||||
|
if (dwFlags & MPPF_INITIALSELECT)
|
||||||
|
dwFlags = (dwFlags ^ MPPF_INITIALSELECT) | MPPF_FINALSELECT;
|
||||||
|
else if (dwFlags & MPPF_FINALSELECT)
|
||||||
|
dwFlags = (dwFlags ^ MPPF_FINALSELECT) | MPPF_INITIALSELECT;
|
||||||
|
}
|
||||||
|
|
||||||
m_ShowFlags = dwFlags;
|
m_ShowFlags = dwFlags;
|
||||||
m_Shown = true;
|
m_Shown = true;
|
||||||
|
|
||||||
|
|
|
@ -777,7 +777,7 @@ HRESULT CMenuFocusManager::UpdateFocus()
|
||||||
CComPtr<IServiceProvider> bandSite;
|
CComPtr<IServiceProvider> bandSite;
|
||||||
CComPtr<IOleWindow> deskBar;
|
CComPtr<IOleWindow> deskBar;
|
||||||
hr = topMenu->mb->GetSite(IID_PPV_ARG(IServiceProvider, &bandSite));
|
hr = topMenu->mb->GetSite(IID_PPV_ARG(IServiceProvider, &bandSite));
|
||||||
hr = bandSite->QueryService(SID_SMenuBandParent, IID_PPV_ARG(IOleWindow, &deskBar));
|
hr = bandSite->QueryService(SID_SMenuPopup, IID_PPV_ARG(IOleWindow, &deskBar));
|
||||||
|
|
||||||
CComPtr<IOleWindow> deskBarSite;
|
CComPtr<IOleWindow> deskBarSite;
|
||||||
hr = IUnknown_GetSite(deskBar, IID_PPV_ARG(IOleWindow, &deskBarSite));
|
hr = IUnknown_GetSite(deskBar, IID_PPV_ARG(IOleWindow, &deskBarSite));
|
||||||
|
|
|
@ -684,32 +684,32 @@ HRESULT CMenuToolbarBase::PopupSubMenu(UINT iItem, UINT index, IShellMenu* child
|
||||||
{
|
{
|
||||||
// Calculate the submenu position and exclude area
|
// Calculate the submenu position and exclude area
|
||||||
RECT rc = { 0 };
|
RECT rc = { 0 };
|
||||||
RECT rcx = { 0 };
|
|
||||||
|
|
||||||
if (!GetItemRect(index, &rc))
|
if (!GetItemRect(index, &rc))
|
||||||
return E_FAIL;
|
return E_FAIL;
|
||||||
|
|
||||||
HWND topWnd;
|
|
||||||
GetWindow(&topWnd);
|
|
||||||
GetWindowRect(topWnd, &rcx);
|
|
||||||
|
|
||||||
POINT a = { rc.left, rc.top };
|
POINT a = { rc.left, rc.top };
|
||||||
POINT b = { rc.right, rc.bottom };
|
POINT b = { rc.right, rc.bottom };
|
||||||
POINT c = { rcx.left, rcx.top };
|
|
||||||
POINT d = { rcx.right, rcx.bottom };
|
|
||||||
|
|
||||||
ClientToScreen(m_hWnd, &a);
|
ClientToScreen(m_hWnd, &a);
|
||||||
ClientToScreen(m_hWnd, &b);
|
ClientToScreen(m_hWnd, &b);
|
||||||
ClientToScreen(topWnd, &c);
|
|
||||||
ClientToScreen(topWnd, &d);
|
|
||||||
|
|
||||||
POINTL pt = { a.x, b.y };
|
POINTL pt = { a.x, b.y };
|
||||||
RECTL rcl = { c.x, c.y, d.x, d.y };
|
RECTL rcl = { a.x, a.y, b.x, b.y };
|
||||||
|
|
||||||
if (m_initFlags & SMINIT_VERTICAL)
|
if (m_initFlags & SMINIT_VERTICAL)
|
||||||
{
|
{
|
||||||
pt.x = b.x - 3;
|
// FIXME: Hardcoding this here feels hacky.
|
||||||
pt.y = a.y - 3;
|
if (IsAppThemed())
|
||||||
|
{
|
||||||
|
pt.x = b.x - 1;
|
||||||
|
pt.y = a.y - 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pt.x = b.x - 3;
|
||||||
|
pt.y = a.y - 3;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Display the submenu
|
// Display the submenu
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue