Author: dquintana
Date: Mon Jan 12 18:03:39 2015
New Revision: 66030
URL:
http://svn.reactos.org/svn/reactos?rev=66030&view=rev
Log:
[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.
Modified:
trunk/reactos/base/shell/explorer/traywnd.cpp
trunk/reactos/base/shell/rshell/CMenuDeskBar.cpp
trunk/reactos/base/shell/rshell/CMenuFocusManager.cpp
trunk/reactos/base/shell/rshell/CMenuToolbars.cpp
Modified: trunk/reactos/base/shell/explorer/traywnd.cpp
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/base/shell/explorer/traywn…
==============================================================================
--- trunk/reactos/base/shell/explorer/traywnd.cpp [iso-8859-1] (original)
+++ trunk/reactos/base/shell/explorer/traywnd.cpp [iso-8859-1] Mon Jan 12 18:03:39 2015
@@ -1972,18 +1972,22 @@
case ABE_BOTTOM:
pt.x = rcExclude.left;
pt.y = rcExclude.top;
+ dwFlags |= MPPF_TOP;
+ break;
+ case ABE_TOP:
+ pt.x = rcExclude.left;
+ pt.y = rcExclude.bottom;
dwFlags |= MPPF_BOTTOM;
break;
- case ABE_TOP:
case ABE_LEFT:
- pt.x = rcExclude.left;
- pt.y = rcExclude.bottom;
- dwFlags |= MPPF_TOP | MPPF_ALIGN_RIGHT;
+ pt.x = rcExclude.right;
+ pt.y = rcExclude.top;
+ dwFlags |= MPPF_RIGHT;
break;
case ABE_RIGHT:
- pt.x = rcExclude.right;
- pt.y = rcExclude.bottom;
- dwFlags |= MPPF_TOP | MPPF_ALIGN_LEFT;
+ pt.x = rcExclude.left;
+ pt.y = rcExclude.top;
+ dwFlags |= MPPF_LEFT;
break;
}
Modified: trunk/reactos/base/shell/rshell/CMenuDeskBar.cpp
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/base/shell/rshell/CMenuDes…
==============================================================================
--- trunk/reactos/base/shell/rshell/CMenuDeskBar.cpp [iso-8859-1] (original)
+++ trunk/reactos/base/shell/rshell/CMenuDeskBar.cpp [iso-8859-1] Mon Jan 12 18:03:39
2015
@@ -268,6 +268,37 @@
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 hr;
@@ -321,58 +352,142 @@
RECT 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 y = ppt->y;
int cx = rc.right - rc.left;
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:
- x = ppt->x;
- y = ppt->y - rc.bottom;
+ alignTop = FALSE;
+ preferVertical = TRUE;
break;
case MPPF_RIGHT:
- x = ppt->x + rc.left;
- y = ppt->y + rc.top;
+ alignLeft = FALSE;
break;
- case MPPF_TOP | MPPF_ALIGN_LEFT:
- x = ppt->x - rc.right;
- y = ppt->y + rc.top;
- break;
- case MPPF_TOP | MPPF_ALIGN_RIGHT:
+ }
+
+ // Try the selected alignment and verify that it doesn't escape the work area.
+ if (alignLeft)
+ {
+ x = ppt->x - cx;
+ }
+ else
+ {
x = ppt->x;
- y = ppt->y + rc.top;
- break;
- }
+ }
+
+ 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)
- {
- // FIXME: Works, but it's oversimplified.
- x = prcExclude->left - cx;
- dwFlags = (dwFlags & (~MPPF_TOP)) | MPPF_LEFT;
- }
+ x = rcWorkArea.right - cx;
if (y < rcWorkArea.top)
- {
y = rcWorkArea.top;
- }
-
- if (cy > waHeight)
- {
- cy = waHeight;
- }
+
+ if (cy > cyWorkArea)
+ cy = cyWorkArea;
if (y + cy > rcWorkArea.bottom)
- {
y = rcWorkArea.bottom - cy;
- }
int flags = SWP_SHOWWINDOW | SWP_NOACTIVATE;
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_Shown = true;
Modified: trunk/reactos/base/shell/rshell/CMenuFocusManager.cpp
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/base/shell/rshell/CMenuFoc…
==============================================================================
--- trunk/reactos/base/shell/rshell/CMenuFocusManager.cpp [iso-8859-1] (original)
+++ trunk/reactos/base/shell/rshell/CMenuFocusManager.cpp [iso-8859-1] Mon Jan 12 18:03:39
2015
@@ -777,7 +777,7 @@
CComPtr<IServiceProvider> bandSite;
CComPtr<IOleWindow> deskBar;
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;
hr = IUnknown_GetSite(deskBar, IID_PPV_ARG(IOleWindow, &deskBarSite));
Modified: trunk/reactos/base/shell/rshell/CMenuToolbars.cpp
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/base/shell/rshell/CMenuToo…
==============================================================================
--- trunk/reactos/base/shell/rshell/CMenuToolbars.cpp [iso-8859-1] (original)
+++ trunk/reactos/base/shell/rshell/CMenuToolbars.cpp [iso-8859-1] Mon Jan 12 18:03:39
2015
@@ -684,32 +684,32 @@
{
// Calculate the submenu position and exclude area
RECT rc = { 0 };
- RECT rcx = { 0 };
if (!GetItemRect(index, &rc))
return E_FAIL;
-
- HWND topWnd;
- GetWindow(&topWnd);
- GetWindowRect(topWnd, &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_hWnd, &a);
ClientToScreen(m_hWnd, &b);
- ClientToScreen(topWnd, &c);
- ClientToScreen(topWnd, &d);
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)
{
- pt.x = b.x - 3;
- pt.y = a.y - 3;
+ // FIXME: Hardcoding this here feels hacky.
+ 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