Blob Blame History Raw
From 0881ae68b0d7f977003e0798e52548caa2556f44 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Caol=C3=A1n=20McNamara?= <caolanm@redhat.com>
Date: Tue, 29 Oct 2013 16:10:18 +0000
Subject: [PATCH] Resolves: rhbz#1021915 force menubar menus to be up/down only

If a menu won't fit in the desired location the default mode is to place it
somewhere it will fit.  e.g. above, left, right. For some cases, e.g. menubars,
it's desirable to limit the options to above/below and force the menu to scroll
if it won't fit

Change-Id: I1998a842d25752389ec9032e54673408d1ed6cb5
---
 include/vcl/floatwin.hxx   |  1 +
 include/vcl/menu.hxx       | 17 +++++++++++------
 vcl/source/window/menu.cxx | 34 ++++++++++++++++++++++++++++------
 3 files changed, 40 insertions(+), 12 deletions(-)

diff --git a/include/vcl/floatwin.hxx b/include/vcl/floatwin.hxx
index 4e2f97c..9a9dbdc 100644
--- a/include/vcl/floatwin.hxx
+++ b/include/vcl/floatwin.hxx
@@ -48,6 +48,7 @@ class ToolBox;
 #define FLOATWIN_POPUPMODE_NEWLEVEL             ((sal_uLong)0x00008000)
 #define FLOATWIN_POPUPMODE_NOMOUSEUPCLOSE       ((sal_uLong)0x00010000)
 #define FLOATWIN_POPUPMODE_GRABFOCUS            ((sal_uLong)0x00020000)
+#define FLOATWIN_POPUPMODE_NOHORZPLACEMENT      ((sal_uLong)0x00040000)
 
 #define FLOATWIN_POPUPMODEEND_CANCEL            ((sal_uInt16)0x0001)
 #define FLOATWIN_POPUPMODEEND_TEAROFF           ((sal_uInt16)0x0002)
diff --git a/include/vcl/menu.hxx b/include/vcl/menu.hxx
index 5579149..637c701 100644
--- a/include/vcl/menu.hxx
+++ b/include/vcl/menu.hxx
@@ -62,12 +62,17 @@ namespace vcl { struct MenuLayoutData; }
 #define MENU_APPEND             ((sal_uInt16)0xFFFF)
 #define MENU_ITEM_NOTFOUND      ((sal_uInt16)0xFFFF)
 
-#define POPUPMENU_EXECUTE_DOWN  ((sal_uInt16)0x0001)
-#define POPUPMENU_EXECUTE_UP    ((sal_uInt16)0x0002)
-#define POPUPMENU_EXECUTE_LEFT  ((sal_uInt16)0x0004)
-#define POPUPMENU_EXECUTE_RIGHT ((sal_uInt16)0x0008)
-
-#define POPUPMENU_NOMOUSEUPCLOSE ((sal_uInt16)0x0010)
+#define POPUPMENU_EXECUTE_DOWN     ((sal_uInt16)0x0001)
+#define POPUPMENU_EXECUTE_UP       ((sal_uInt16)0x0002)
+#define POPUPMENU_EXECUTE_LEFT     ((sal_uInt16)0x0004)
+#define POPUPMENU_EXECUTE_RIGHT    ((sal_uInt16)0x0008)
+#define POPUPMENU_NOMOUSEUPCLOSE   ((sal_uInt16)0x0010)
+//If there isn't enough space to put the menu where it wants
+//to go, then they will be autoplaced. Toggle this bit
+//on to force menus to be placed either above or below
+//the starting rectangle and shrunk to fit and then scroll rather than place
+//the menu beside that rectangle
+#define POPUPMENU_NOHORZ_PLACEMENT ((sal_uInt16)0x0020)
 
 #define MENU_FLAG_NOAUTOMNEMONICS       0x0001
 #define MENU_FLAG_HIDEDISABLEDENTRIES   0x0002
diff --git a/vcl/source/window/menu.cxx b/vcl/source/window/menu.cxx
index f567ba3..6083554 100644
--- a/vcl/source/window/menu.cxx
+++ b/vcl/source/window/menu.cxx
@@ -3581,7 +3581,6 @@
 {
     ENSURE_OR_RETURN( pExecWindow, "PopupMenu::Execute: need a non-NULL window!", 0 );
 
-
     sal_uLong nPopupModeFlags = 0;
     if ( nFlags & POPUPMENU_EXECUTE_DOWN )
         nPopupModeFlags = FLOATWIN_POPUPMODE_DOWN;
@@ -3597,6 +3596,9 @@
     if (nFlags & POPUPMENU_NOMOUSEUPCLOSE )                      // allow popup menus to stay open on mouse button up
         nPopupModeFlags |= FLOATWIN_POPUPMODE_NOMOUSEUPCLOSE;    // useful if the menu was opened on mousebutton down (eg toolbox configuration)
 
+    if (nFlags & POPUPMENU_NOHORZ_PLACEMENT)
+        nPopupModeFlags |= FLOATWIN_POPUPMODE_NOHORZPLACEMENT;
+
     return ImplExecute( pExecWindow, rRect, nPopupModeFlags, 0, sal_False );
 }
 
@@ -3700,17 +3702,37 @@
 
     Size aSz = ImplCalcSize( pWin );
 
-    long nMaxHeight = pWin->GetDesktopRectPixel().GetHeight();
+    Rectangle aDesktopRect(pWin->GetDesktopRectPixel());
     if( Application::GetScreenCount() > 1 && Application::IsUnifiedDisplay() )
     {
         Window* pDeskW = pWindow->GetWindow( WINDOW_REALPARENT );
         if( ! pDeskW )
             pDeskW = pWindow;
         Point aDesktopTL( pDeskW->OutputToAbsoluteScreenPixel( aRect.TopLeft() ) );
-        nMaxHeight = Application::GetWorkAreaPosSizePixel(
-            Application::GetBestScreen( Rectangle( aDesktopTL, aRect.GetSize() ) )
-            ).GetHeight();
+        aDesktopRect = Application::GetWorkAreaPosSizePixel(
+            Application::GetBestScreen( Rectangle( aDesktopTL, aRect.GetSize() ) ));
     }
+
+    long nMaxHeight = aDesktopRect.GetHeight();
+
+    //rhbz#1021915. If a menu won't fit in the desired location the default
+    //mode is to place it somewhere it will fit.  e.g. above, left, right. For
+    //some cases, e.g. menubars, it's desirable to limit the options to
+    //above/below and force the menu to scroll if it won't fit
+    if (nPopupModeFlags & FLOATWIN_POPUPMODE_NOHORZPLACEMENT)
+    {
+        Window* pRef = pWin;
+        if ( pRef->GetParent() )
+            pRef = pRef->GetParent();
+
+        Rectangle devRect(  pRef->OutputToAbsoluteScreenPixel( aRect.TopLeft() ),
+                            pRef->OutputToAbsoluteScreenPixel( aRect.BottomRight() ) );
+
+        long nHeightAbove = devRect.Top() - aDesktopRect.Top();
+        long nHeightBelow = aDesktopRect.Bottom() - devRect.Bottom();
+        nMaxHeight = std::min(nMaxHeight, std::max(nHeightAbove, nHeightBelow));
+    }
+
     if ( pStartedFrom && pStartedFrom->bIsMenuBar )
         nMaxHeight -= pW->GetSizePixel().Height();
     sal_Int32 nLeft, nTop, nRight, nBottom;
@@ -5345,7 +5367,7 @@
             // #99071# do not grab the focus, otherwise it will be restored to the menubar
             // when the frame is reactivated later
             //GrabFocus();
-            pActivePopup->ImplExecute( this, Rectangle( aItemTopLeft, aItemBottomRight ), FLOATWIN_POPUPMODE_DOWN, pMenu, bPreSelectFirst );
+            pActivePopup->ImplExecute( this, Rectangle( aItemTopLeft, aItemBottomRight ), FLOATWIN_POPUPMODE_DOWN | FLOATWIN_POPUPMODE_NOHORZPLACEMENT, pMenu, bPreSelectFirst );
             if ( pActivePopup )
             {
                 // does not have a window, if aborted before or if there are no entries