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