summaryrefslogtreecommitdiff
path: root/vcl
diff options
context:
space:
mode:
Diffstat (limited to 'vcl')
-rw-r--r--vcl/Library_vcl.mk3
-rw-r--r--vcl/source/window/menu.cxx1902
-rw-r--r--vcl/source/window/menufloatingwindow.cxx1209
-rw-r--r--vcl/source/window/menufloatingwindow.hxx121
-rw-r--r--vcl/source/window/menuitemlist.cxx280
-rw-r--r--vcl/source/window/menuitemlist.hxx152
-rw-r--r--vcl/source/window/menuwindow.cxx161
-rw-r--r--vcl/source/window/menuwindow.hxx49
8 files changed, 2049 insertions, 1828 deletions
diff --git a/vcl/Library_vcl.mk b/vcl/Library_vcl.mk
index 227372d9c7f6..ec50fddb2c57 100644
--- a/vcl/Library_vcl.mk
+++ b/vcl/Library_vcl.mk
@@ -138,6 +138,9 @@ $(eval $(call gb_Library_add_exception_objects,vcl,\
vcl/source/window/keyevent \
vcl/source/window/layout \
vcl/source/window/menu \
+ vcl/source/window/menufloatingwindow \
+ vcl/source/window/menuitemlist \
+ vcl/source/window/menuwindow \
vcl/source/window/mnemonic \
vcl/source/window/mnemonicengine \
vcl/source/window/mouse \
diff --git a/vcl/source/window/menu.cxx b/vcl/source/window/menu.cxx
index a36a37b37ba8..096738034b60 100644
--- a/vcl/source/window/menu.cxx
+++ b/vcl/source/window/menu.cxx
@@ -17,30 +17,30 @@
* the License at http://www.apache.org/licenses/LICENSE-2.0 .
*/
-#include "tools/debug.hxx"
-#include "tools/diagnose_ex.h"
-#include "tools/rc.h"
-#include "tools/stream.hxx"
-
-#include "vcl/svapp.hxx"
-#include "vcl/mnemonic.hxx"
-#include "vcl/image.hxx"
-#include "vcl/event.hxx"
-#include "vcl/help.hxx"
-#include "vcl/floatwin.hxx"
-#include "vcl/wrkwin.hxx"
-#include "vcl/timer.hxx"
-#include "vcl/decoview.hxx"
-#include "vcl/bitmap.hxx"
-#include "vcl/menu.hxx"
-#include "vcl/button.hxx"
-#include "vcl/gradient.hxx"
-#include "vcl/i18nhelp.hxx"
-#include "vcl/taskpanelist.hxx"
-#include "vcl/controllayout.hxx"
-#include "vcl/toolbox.hxx"
-#include "vcl/dockingarea.hxx"
-#include "vcl/settings.hxx"
+#include <tools/debug.hxx>
+#include <tools/diagnose_ex.h>
+#include <tools/rc.h>
+#include <tools/stream.hxx>
+
+#include <vcl/svapp.hxx>
+#include <vcl/mnemonic.hxx>
+#include <vcl/image.hxx>
+#include <vcl/event.hxx>
+#include <vcl/help.hxx>
+#include <vcl/floatwin.hxx>
+#include <vcl/wrkwin.hxx>
+#include <vcl/timer.hxx>
+#include <vcl/decoview.hxx>
+#include <vcl/bitmap.hxx>
+#include <vcl/menu.hxx>
+#include <vcl/button.hxx>
+#include <vcl/gradient.hxx>
+#include <vcl/i18nhelp.hxx>
+#include <vcl/taskpanelist.hxx>
+#include <vcl/controllayout.hxx>
+#include <vcl/toolbox.hxx>
+#include <vcl/dockingarea.hxx>
+#include <vcl/settings.hxx>
#include "salinst.hxx"
#include "svdata.hxx"
@@ -48,9 +48,10 @@
#include "window.h"
#include "salmenu.hxx"
#include "salframe.hxx"
+#include "menufloatingwindow.hxx"
+#include "menuitemlist.hxx"
#include <com/sun/star/uno/Reference.h>
-#include <com/sun/star/i18n/XCharacterClassification.hpp>
#include <com/sun/star/lang/XComponent.hpp>
#include <com/sun/star/accessibility/XAccessible.hpp>
#include <com/sun/star/accessibility/AccessibleRole.hpp>
@@ -79,11 +80,7 @@ struct MenuLayoutData : public ControlLayoutData
using namespace ::com::sun::star;
using namespace vcl;
-#define ITEMPOS_INVALID 0xFFFF
-
-#define EXTRASPACEY 2
#define EXTRAITEMHEIGHT 4
-#define GUTTERBORDER 8
// document closer
#define IID_DOCUMENTCLOSE 1
@@ -103,463 +100,6 @@ static bool ImplAccelDisabled()
return nAccelDisabled == 1;
}
-struct MenuItemData
-{
- sal_uInt16 nId; // SV Id
- MenuItemType eType; // MenuItem-Type
- MenuItemBits nBits; // MenuItem-Bits
- Menu* pSubMenu; // Pointer to SubMenu
- Menu* pAutoSubMenu; // Pointer to SubMenu from Resource
- OUString aText; // Menu-Text
- OUString aHelpText; // Help-String
- OUString aTipHelpText; // TipHelp-String (eg, expanded filenames)
- OUString aCommandStr; // CommandString
- OUString aHelpCommandStr; // Help command string (to reference external help)
- OString sIdent;
- OString aHelpId; // Help-Id
- sal_uLong nUserValue; // User value
- Image aImage; // Image
- KeyCode aAccelKey; // Accelerator-Key
- bool bChecked; // Checked
- bool bEnabled; // Enabled
- bool bVisible; // Visible (note: this flag will not override MENU_FLAG_HIDEDISABLEDENTRIES when true)
- bool bIsTemporary; // Temporary inserted ('No selection possible')
- bool bMirrorMode;
- long nItemImageAngle;
- Size aSz; // only temporarily valid
- OUString aAccessibleName; // accessible name
- OUString aAccessibleDescription; // accessible description
-
- SalMenuItem* pSalMenuItem; // access to native menu
-
- MenuItemData()
- : nId(0)
- , eType(MENUITEM_DONTKNOW)
- , nBits(0)
- , pSubMenu(NULL)
- , pAutoSubMenu(NULL)
- , nUserValue(0)
- , bChecked(false)
- , bEnabled(false)
- , bVisible(false)
- , bIsTemporary(false)
- , bMirrorMode(false)
- , nItemImageAngle(0)
- , pSalMenuItem(NULL)
- {
- }
- MenuItemData( const OUString& rStr, const Image& rImage )
- : nId(0)
- , eType(MENUITEM_DONTKNOW)
- , nBits(0)
- , pSubMenu(NULL)
- , pAutoSubMenu(NULL)
- , aText(rStr)
- , nUserValue(0)
- , aImage(rImage)
- , bChecked(false)
- , bEnabled(false)
- , bVisible(false)
- , bIsTemporary(false)
- , bMirrorMode(false)
- , nItemImageAngle(0)
- , pSalMenuItem(NULL)
- {
- }
- ~MenuItemData();
- bool HasCheck() const
- {
- return bChecked || ( nBits & ( MIB_RADIOCHECK | MIB_CHECKABLE | MIB_AUTOCHECK ) );
- }
-};
-
-MenuItemData::~MenuItemData()
-{
- if( pAutoSubMenu )
- {
- ((PopupMenu*)pAutoSubMenu)->pRefAutoSubMenu = NULL;
- delete pAutoSubMenu;
- pAutoSubMenu = NULL;
- }
- if( pSalMenuItem )
- ImplGetSVData()->mpDefInst->DestroyMenuItem( pSalMenuItem );
-}
-
-class MenuItemList
-{
-private:
- typedef ::std::vector< MenuItemData* > MenuItemDataList_impl;
- MenuItemDataList_impl maItemList;
-
- uno::Reference< i18n::XCharacterClassification > xCharClass;
-
-public:
- MenuItemList() {}
- ~MenuItemList();
-
- MenuItemData* Insert(
- sal_uInt16 nId,
- MenuItemType eType,
- MenuItemBits nBits,
- const OUString& rStr,
- const Image& rImage,
- Menu* pMenu,
- size_t nPos,
- const OString &rIdent
- );
- void InsertSeparator(const OString &rIdent, size_t nPos);
- void Remove( size_t nPos );
-
- MenuItemData* GetData( sal_uInt16 nSVId, size_t& rPos ) const;
- MenuItemData* GetData( sal_uInt16 nSVId ) const
- {
- size_t nTemp;
- return GetData( nSVId, nTemp );
- }
- MenuItemData* GetDataFromPos( size_t nPos ) const
- {
- return ( nPos < maItemList.size() ) ? maItemList[ nPos ] : NULL;
- }
-
- MenuItemData* SearchItem(
- sal_Unicode cSelectChar,
- KeyCode aKeyCode,
- sal_uInt16& rPos,
- sal_uInt16& nDuplicates,
- sal_uInt16 nCurrentPos
- ) const;
- size_t GetItemCount( sal_Unicode cSelectChar ) const;
- size_t GetItemCount( KeyCode aKeyCode ) const;
- size_t size()
- {
- return maItemList.size();
- }
-};
-
-MenuItemList::~MenuItemList()
-{
- for( size_t i = 0, n = maItemList.size(); i < n; ++i )
- delete maItemList[ i ];
-}
-
-MenuItemData* MenuItemList::Insert(
- sal_uInt16 nId,
- MenuItemType eType,
- MenuItemBits nBits,
- const OUString& rStr,
- const Image& rImage,
- Menu* pMenu,
- size_t nPos,
- const OString &rIdent
-)
-{
- MenuItemData* pData = new MenuItemData( rStr, rImage );
- pData->nId = nId;
- pData->sIdent = rIdent;
- pData->eType = eType;
- pData->nBits = nBits;
- pData->pSubMenu = NULL;
- pData->pAutoSubMenu = NULL;
- pData->nUserValue = 0;
- pData->bChecked = false;
- pData->bEnabled = true;
- pData->bVisible = true;
- pData->bIsTemporary = false;
- pData->bMirrorMode = false;
- pData->nItemImageAngle = 0;
-
- SalItemParams aSalMIData;
- aSalMIData.nId = nId;
- aSalMIData.eType = eType;
- aSalMIData.nBits = nBits;
- aSalMIData.pMenu = pMenu;
- aSalMIData.aText = rStr;
- aSalMIData.aImage = rImage;
-
- // Native-support: returns NULL if not supported
- pData->pSalMenuItem = ImplGetSVData()->mpDefInst->CreateMenuItem( &aSalMIData );
-
- if( nPos < maItemList.size() ) {
- maItemList.insert( maItemList.begin() + nPos, pData );
- } else {
- maItemList.push_back( pData );
- }
- return pData;
-}
-
-void MenuItemList::InsertSeparator(const OString &rIdent, size_t nPos)
-{
- MenuItemData* pData = new MenuItemData;
- pData->nId = 0;
- pData->sIdent = rIdent;
- pData->eType = MENUITEM_SEPARATOR;
- pData->nBits = 0;
- pData->pSubMenu = NULL;
- pData->pAutoSubMenu = NULL;
- pData->nUserValue = 0;
- pData->bChecked = false;
- pData->bEnabled = true;
- pData->bVisible = true;
- pData->bIsTemporary = false;
- pData->bMirrorMode = false;
- pData->nItemImageAngle = 0;
-
- SalItemParams aSalMIData;
- aSalMIData.nId = 0;
- aSalMIData.eType = MENUITEM_SEPARATOR;
- aSalMIData.nBits = 0;
- aSalMIData.pMenu = NULL;
- aSalMIData.aText = OUString();
- aSalMIData.aImage = Image();
-
- // Native-support: returns NULL if not supported
- pData->pSalMenuItem = ImplGetSVData()->mpDefInst->CreateMenuItem( &aSalMIData );
-
- if( nPos < maItemList.size() ) {
- maItemList.insert( maItemList.begin() + nPos, pData );
- } else {
- maItemList.push_back( pData );
- }
-}
-
-void MenuItemList::Remove( size_t nPos )
-{
- if( nPos < maItemList.size() )
- {
- delete maItemList[ nPos ];
- maItemList.erase( maItemList.begin() + nPos );
- }
-}
-
-MenuItemData* MenuItemList::GetData( sal_uInt16 nSVId, size_t& rPos ) const
-{
- for( size_t i = 0, n = maItemList.size(); i < n; ++i )
- {
- if ( maItemList[ i ]->nId == nSVId )
- {
- rPos = i;
- return maItemList[ i ];
- }
- }
- return NULL;
-}
-
-MenuItemData* MenuItemList::SearchItem(
- sal_Unicode cSelectChar,
- KeyCode aKeyCode,
- sal_uInt16& rPos,
- sal_uInt16& nDuplicates,
- sal_uInt16 nCurrentPos
-) const
-{
- const vcl::I18nHelper& rI18nHelper = Application::GetSettings().GetUILocaleI18nHelper();
-
- size_t nListCount = maItemList.size();
-
- // try character code first
- nDuplicates = GetItemCount( cSelectChar ); // return number of duplicates
- if( nDuplicates )
- {
- for ( rPos = 0; rPos < nListCount; rPos++)
- {
- MenuItemData* pData = maItemList[ rPos ];
- if ( pData->bEnabled && rI18nHelper.MatchMnemonic( pData->aText, cSelectChar ) )
- {
- if( nDuplicates > 1 && rPos == nCurrentPos )
- continue; // select next entry with the same mnemonic
- else
- return pData;
- }
- }
- }
-
- // nothing found, try keycode instead
- nDuplicates = GetItemCount( aKeyCode ); // return number of duplicates
-
- if( nDuplicates )
- {
- char ascii = 0;
- if( aKeyCode.GetCode() >= KEY_A && aKeyCode.GetCode() <= KEY_Z )
- ascii = sal::static_int_cast<char>('A' + (aKeyCode.GetCode() - KEY_A));
-
- for ( rPos = 0; rPos < nListCount; rPos++)
- {
- MenuItemData* pData = maItemList[ rPos ];
- if ( pData->bEnabled )
- {
- sal_Int32 n = pData->aText.indexOf('~');
- if ( n != -1 )
- {
- KeyCode mnKeyCode;
- sal_Unicode mnUnicode = pData->aText[n+1];
- Window* pDefWindow = ImplGetDefaultWindow();
- if( ( pDefWindow
- && pDefWindow->ImplGetFrame()->MapUnicodeToKeyCode( mnUnicode,
- Application::GetSettings().GetUILanguageTag().getLanguageType(), mnKeyCode )
- && aKeyCode.GetCode() == mnKeyCode.GetCode()
- )
- || ( ascii
- && rI18nHelper.MatchMnemonic( pData->aText, ascii )
- )
- )
- {
- if( nDuplicates > 1 && rPos == nCurrentPos )
- continue; // select next entry with the same mnemonic
- else
- return pData;
- }
- }
- }
- }
- }
-
- return NULL;
-}
-
-size_t MenuItemList::GetItemCount( sal_Unicode cSelectChar ) const
-{
- // returns number of entries with same mnemonic
- const vcl::I18nHelper& rI18nHelper = Application::GetSettings().GetUILocaleI18nHelper();
-
- size_t nItems = 0;
- for ( size_t nPos = maItemList.size(); nPos; )
- {
- MenuItemData* pData = maItemList[ --nPos ];
- if ( pData->bEnabled && rI18nHelper.MatchMnemonic( pData->aText, cSelectChar ) )
- nItems++;
- }
-
- return nItems;
-}
-
-size_t MenuItemList::GetItemCount( KeyCode aKeyCode ) const
-{
- // returns number of entries with same mnemonic
- // uses key codes instead of character codes
- const vcl::I18nHelper& rI18nHelper = Application::GetSettings().GetUILocaleI18nHelper();
- char ascii = 0;
- if( aKeyCode.GetCode() >= KEY_A && aKeyCode.GetCode() <= KEY_Z )
- ascii = sal::static_int_cast<char>('A' + (aKeyCode.GetCode() - KEY_A));
-
- size_t nItems = 0;
- for ( size_t nPos = maItemList.size(); nPos; )
- {
- MenuItemData* pData = maItemList[ --nPos ];
- if ( pData->bEnabled )
- {
- sal_Int32 n = pData->aText.indexOf('~');
- if (n != -1)
- {
- KeyCode mnKeyCode;
- // if MapUnicodeToKeyCode fails or is unsupported we try the pure ascii mapping of the keycodes
- // so we have working shortcuts when ascii mnemonics are used
- Window* pDefWindow = ImplGetDefaultWindow();
- if( ( pDefWindow
- && pDefWindow->ImplGetFrame()->MapUnicodeToKeyCode( pData->aText[n+1],
- Application::GetSettings().GetUILanguageTag().getLanguageType(), mnKeyCode )
- && aKeyCode.GetCode() == mnKeyCode.GetCode()
- )
- || ( ascii
- && rI18nHelper.MatchMnemonic( pData->aText, ascii )
- )
- )
- nItems++;
- }
- }
- }
-
- return nItems;
-}
-
-// - MenuFloatingWindow -
-
-class MenuFloatingWindow : public FloatingWindow
-{
- friend void Menu::ImplFillLayoutData() const;
- friend Menu::~Menu();
-
-private:
- Menu* pMenu;
- PopupMenu* pActivePopup;
- Timer aHighlightChangedTimer;
- Timer aSubmenuCloseTimer;
- Timer aScrollTimer;
- sal_uLong nSaveFocusId;
- sal_uInt16 nHighlightedItem; // highlighted/selected Item
- sal_uInt16 nMBDownPos;
- sal_uInt16 nScrollerHeight;
- sal_uInt16 nFirstEntry;
- sal_uInt16 nBorder;
- sal_uInt16 nPosInParent;
- bool bInExecute;
-
- bool bScrollMenu;
- bool bScrollUp;
- bool bScrollDown;
- bool bIgnoreFirstMove;
- bool bKeyInput;
-
- DECL_LINK(PopupEnd, void *);
- DECL_LINK( HighlightChanged, Timer* );
- DECL_LINK(SubmenuClose, void *);
- DECL_LINK(AutoScroll, void *);
- DECL_LINK( ShowHideListener, VclWindowEvent* );
-
- virtual void StateChanged( StateChangedType nType ) SAL_OVERRIDE;
- virtual void DataChanged( const DataChangedEvent& rDCEvt ) SAL_OVERRIDE;
-
- void InitMenuClipRegion();
-
-protected:
- Region ImplCalcClipRegion( bool bIncludeLogo = true ) const;
- void ImplDrawScroller( bool bUp );
- using Window::ImplScroll;
- void ImplScroll( const Point& rMousePos );
- void ImplScroll( bool bUp );
- void ImplCursorUpDown( bool bUp, bool bHomeEnd = false );
- void ImplHighlightItem( const MouseEvent& rMEvt, bool bMBDown );
- long ImplGetStartY() const;
- Rectangle ImplGetItemRect( sal_uInt16 nPos );
-
-public:
- MenuFloatingWindow( Menu* pMenu, Window* pParent, WinBits nStyle );
- virtual ~MenuFloatingWindow();
-
- void doShutdown();
-
- virtual void MouseMove( const MouseEvent& rMEvt ) SAL_OVERRIDE;
- virtual void MouseButtonDown( const MouseEvent& rMEvt ) SAL_OVERRIDE;
- virtual void MouseButtonUp( const MouseEvent& rMEvt ) SAL_OVERRIDE;
- virtual void KeyInput( const KeyEvent& rKEvent ) SAL_OVERRIDE;
- virtual void Command( const CommandEvent& rCEvt ) SAL_OVERRIDE;
- virtual void Paint( const Rectangle& rRect ) SAL_OVERRIDE;
- virtual void RequestHelp( const HelpEvent& rHEvt ) SAL_OVERRIDE;
- virtual void Resize() SAL_OVERRIDE;
-
- void SetFocusId( sal_uLong nId ) { nSaveFocusId = nId; }
- sal_uLong GetFocusId() const { return nSaveFocusId; }
-
- void EnableScrollMenu( bool b );
- bool IsScrollMenu() const { return bScrollMenu; }
- sal_uInt16 GetScrollerHeight() const { return nScrollerHeight; }
-
- void Execute();
- void StopExecute( sal_uLong nFocusId = 0 );
- void EndExecute();
- void EndExecute( sal_uInt16 nSelectId );
-
- PopupMenu* GetActivePopup() const { return pActivePopup; }
- void KillActivePopup( PopupMenu* pThisOnly = NULL );
-
- void HighlightItem( sal_uInt16 nPos, bool bHighlight );
- void ChangeHighlightItem( sal_uInt16 n, bool bStartPopupTimer );
- sal_uInt16 GetHighlightedItem() const { return nHighlightedItem; }
-
- void SetPosInParent( sal_uInt16 nPos ) { nPosInParent = nPos; }
-
- virtual ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible > CreateAccessible() SAL_OVERRIDE;
-};
-
// To get the transparent mouse-over look, the closer is actually a toolbox
// overload DataChange to handle style changes correctly
class DecoToolBox : public ToolBox
@@ -670,7 +210,7 @@ void DecoToolBox::SetImages( long nMaxHeight, bool bForce )
// In most functions we would have to create exceptions for
// menubar, popupmenu, hence we made two classes
-class MenuBarWindow : public Window
+class MenuBarWindow : public MenuWindow, public Window
{
friend class MenuBar;
friend class Menu;
@@ -783,87 +323,6 @@ static void ImplSetMenuItemData( MenuItemData* pData )
pData->eType = MENUITEM_STRINGIMAGE;
}
-static sal_uLong ImplChangeTipTimeout( sal_uLong nTimeout, Window *pWindow )
-{
- AllSettings aAllSettings( pWindow->GetSettings() );
- HelpSettings aHelpSettings( aAllSettings.GetHelpSettings() );
- sal_uLong nRet = aHelpSettings.GetTipTimeout();
- aHelpSettings.SetTipTimeout( nTimeout );
- aAllSettings.SetHelpSettings( aHelpSettings );
- pWindow->SetSettings( aAllSettings );
- return nRet;
-}
-
-static bool ImplHandleHelpEvent( Window* pMenuWindow, Menu* pMenu, sal_uInt16 nHighlightedItem, const HelpEvent& rHEvt, const Rectangle &rHighlightRect )
-{
- if( ! pMenu )
- return false;
-
- bool bDone = false;
- sal_uInt16 nId = 0;
-
- if ( nHighlightedItem != ITEMPOS_INVALID )
- {
- MenuItemData* pItemData = pMenu->GetItemList()->GetDataFromPos( nHighlightedItem );
- if ( pItemData )
- nId = pItemData->nId;
- }
-
- if ( ( rHEvt.GetMode() & HELPMODE_BALLOON ) && pMenuWindow )
- {
- Point aPos;
- if( rHEvt.KeyboardActivated() )
- aPos = rHighlightRect.Center();
- else
- aPos = rHEvt.GetMousePosPixel();
-
- Rectangle aRect( aPos, Size() );
- if (!pMenu->GetHelpText(nId).isEmpty())
- Help::ShowBalloon( pMenuWindow, aPos, pMenu->GetHelpText( nId ) );
- else
- {
- // give user a chance to read the full filename
- sal_uLong oldTimeout=ImplChangeTipTimeout( 60000, pMenuWindow );
- // call always, even when strlen==0 to correctly remove tip
- Help::ShowQuickHelp( pMenuWindow, aRect, pMenu->GetTipHelpText( nId ) );
- ImplChangeTipTimeout( oldTimeout, pMenuWindow );
- }
- bDone = true;
- }
- else if ( ( rHEvt.GetMode() & HELPMODE_QUICK ) && pMenuWindow )
- {
- Point aPos = rHEvt.GetMousePosPixel();
- Rectangle aRect( aPos, Size() );
- // give user a chance to read the full filename
- sal_uLong oldTimeout=ImplChangeTipTimeout( 60000, pMenuWindow );
- // call always, even when strlen==0 to correctly remove tip
- Help::ShowQuickHelp( pMenuWindow, aRect, pMenu->GetTipHelpText( nId ) );
- ImplChangeTipTimeout( oldTimeout, pMenuWindow );
- bDone = true;
- }
- else if ( rHEvt.GetMode() & (HELPMODE_CONTEXT | HELPMODE_EXTENDED) )
- {
- // is help in the application selected
- Help* pHelp = Application::GetHelp();
- if ( pHelp )
- {
- // is an id available, then call help with the id, otherwise
- // use help-index
- OUString aCommand = pMenu->GetItemCommand( nId );
- OString aHelpId( pMenu->GetHelpId( nId ) );
- if( aHelpId.isEmpty() )
- aHelpId = OOO_HELP_INDEX;
-
- if ( !aCommand.isEmpty() )
- pHelp->Start( aCommand, NULL );
- else
- pHelp->Start( OStringToOUString( aHelpId, RTL_TEXTENCODING_UTF8 ), NULL );
- }
- bDone = true;
- }
- return bDone;
-}
-
static int ImplGetTopDockingAreaHeight( Window *pWindow )
{
// find docking area that is top aligned and return its height
@@ -3070,6 +2529,53 @@ bool Menu::HasValidEntries( bool bCheckPopups )
return bValidEntries;
}
+void Menu::CloseStartedFrom()
+{
+ // if the window was closed by TH, there is another menu
+ // which has this window as pActivePopup
+ if (!pStartedFrom)
+ return;
+
+ // pWin from parent could be 0, if the list is
+ // cleaned from the start, now clean up the endpopup-events
+ if (pStartedFrom->bIsMenuBar)
+ {
+ MenuBarWindow* p = (MenuBarWindow*) pStartedFrom->ImplGetWindow();
+ if (p)
+ p->PopupClosed(this);
+ }
+ else
+ {
+ MenuFloatingWindow* p = (MenuFloatingWindow*) pStartedFrom->ImplGetWindow();
+ PopupMenu *pMenu = dynamic_cast<PopupMenu*>(this);
+ if (p && pMenu)
+ p->KillActivePopup(pMenu);
+ }
+}
+
+sal_uLong Menu::DeactivateMenuBar(sal_uLong nFocusId)
+{
+ if (!bIsMenuBar)
+ return nFocusId;
+
+ nFocusId = ((MenuBarWindow*)(dynamic_cast<MenuBar*>(this))->ImplGetWindow())->GetFocusId();
+ if (nFocusId)
+ {
+ ((MenuBarWindow*)(dynamic_cast<MenuBar*>(this))->ImplGetWindow())->SetFocusId(0);
+ ImplGetSVData()->maWinData.mbNoDeactivate = false;
+ }
+
+ return nFocusId;
+}
+
+void Menu::MenuBarKeyInput(const KeyEvent& rEvent)
+{
+ if (!bIsMenuBar)
+ return;
+
+ ((MenuBarWindow*)(dynamic_cast<MenuBar*>(this))->ImplGetWindow())->KeyInput(rEvent);
+}
+
void Menu::ImplKillLayoutData() const
{
delete mpLayoutData, mpLayoutData = NULL;
@@ -3861,1266 +3367,6 @@ long PopupMenu::ImplCalcHeight( sal_uInt16 nEntries ) const
return nHeight;
}
-static void ImplInitMenuWindow( Window* pWin, bool bFont, bool bMenuBar )
-{
- const StyleSettings& rStyleSettings = pWin->GetSettings().GetStyleSettings();
-
- if ( bFont )
- pWin->SetPointFont( rStyleSettings.GetMenuFont() );
- if( bMenuBar )
- {
- const BitmapEx& rPersonaBitmap = Application::GetSettings().GetStyleSettings().GetPersonaHeader();
- if ( !rPersonaBitmap.IsEmpty() )
- {
- Wallpaper aWallpaper( rPersonaBitmap );
- aWallpaper.SetStyle( WALLPAPER_TOPRIGHT );
- aWallpaper.SetColor( Application::GetSettings().GetStyleSettings().GetWorkspaceColor() );
-
- pWin->SetBackground( aWallpaper );
- pWin->SetPaintTransparent( false );
- pWin->SetParentClipMode( 0 );
- }
- else if ( pWin->IsNativeControlSupported( CTRL_MENUBAR, PART_ENTIRE_CONTROL ) )
- {
- pWin->SetBackground(); // background will be drawn by NWF
- }
- else
- {
- Wallpaper aWallpaper;
- aWallpaper.SetStyle( WALLPAPER_APPLICATIONGRADIENT );
- pWin->SetBackground( aWallpaper );
- pWin->SetPaintTransparent( false );
- pWin->SetParentClipMode( 0 );
- }
- }
- else
- {
- if( pWin->IsNativeControlSupported( CTRL_MENU_POPUP, PART_ENTIRE_CONTROL ) )
- {
- pWin->SetBackground(); // background will be drawn by NWF
- }
- else
- pWin->SetBackground( Wallpaper( rStyleSettings.GetMenuColor() ) );
- }
-
- if ( bMenuBar )
- pWin->SetTextColor( rStyleSettings.GetMenuBarTextColor() );
- else
- pWin->SetTextColor( rStyleSettings.GetMenuTextColor() );
- pWin->SetTextFillColor();
- pWin->SetLineColor();
-}
-
-MenuFloatingWindow::MenuFloatingWindow( Menu* pMen, Window* pParent, WinBits nStyle ) :
- FloatingWindow( pParent, nStyle )
-{
- mpWindowImpl->mbMenuFloatingWindow= true;
- pMenu = pMen;
- pActivePopup = 0;
- nSaveFocusId = 0;
- bInExecute = false;
- bScrollMenu = false;
- nHighlightedItem = ITEMPOS_INVALID;
- nMBDownPos = ITEMPOS_INVALID;
- nPosInParent = ITEMPOS_INVALID;
- nScrollerHeight = 0;
- nBorder = EXTRASPACEY;
- nFirstEntry = 0;
- bScrollUp = false;
- bScrollDown = false;
- bIgnoreFirstMove = true;
- bKeyInput = false;
-
- EnableSaveBackground();
- ImplInitMenuWindow( this, true, false );
-
- SetPopupModeEndHdl( LINK( this, MenuFloatingWindow, PopupEnd ) );
-
- aHighlightChangedTimer.SetTimeoutHdl( LINK( this, MenuFloatingWindow, HighlightChanged ) );
- aHighlightChangedTimer.SetTimeout( GetSettings().GetMouseSettings().GetMenuDelay() );
- aSubmenuCloseTimer.SetTimeout( GetSettings().GetMouseSettings().GetMenuDelay() );
- aSubmenuCloseTimer.SetTimeoutHdl( LINK( this, MenuFloatingWindow, SubmenuClose ) );
- aScrollTimer.SetTimeoutHdl( LINK( this, MenuFloatingWindow, AutoScroll ) );
-
- AddEventListener( LINK( this, MenuFloatingWindow, ShowHideListener ) );
-}
-
-void MenuFloatingWindow::doShutdown()
-{
- if( pMenu )
- {
- // #105373# notify toolkit that highlight was removed
- // otherwise the entry will not be read when the menu is opened again
- if( nHighlightedItem != ITEMPOS_INVALID )
- pMenu->ImplCallEventListeners( VCLEVENT_MENU_DEHIGHLIGHT, nHighlightedItem );
- pMenu->SetHighlightItem(ITEMPOS_INVALID);
- if( !bKeyInput && pMenu && pMenu->pStartedFrom && !pMenu->pStartedFrom->bIsMenuBar )
- {
- // #102461# remove highlight in parent
- MenuItemData* pData;
- size_t i, nCount = pMenu->pStartedFrom->pItemList->size();
- for(i = 0; i < nCount; i++)
- {
- pData = pMenu->pStartedFrom->pItemList->GetDataFromPos( i );
- if( pData && ( pData->pSubMenu == pMenu ) )
- break;
- }
- if( i < nCount )
- {
- MenuFloatingWindow* pPWin = (MenuFloatingWindow*)pMenu->pStartedFrom->ImplGetWindow();
- if( pPWin )
- pPWin->HighlightItem( i, false );
- }
- }
-
- // free the reference to the accessible component
- SetAccessible( ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible >() );
-
- aHighlightChangedTimer.Stop();
-
- // #95056# invalidate screen area covered by system window
- // so this can be taken into account if the commandhandler performs a scroll operation
- if( GetParent() )
- {
- Rectangle aInvRect( GetWindowExtentsRelative( GetParent() ) );
- GetParent()->Invalidate( aInvRect );
- }
- pMenu = NULL;
- RemoveEventListener( LINK( this, MenuFloatingWindow, ShowHideListener ) );
- }
-}
-
-MenuFloatingWindow::~MenuFloatingWindow()
-{
- doShutdown();
-}
-
-void MenuFloatingWindow::Resize()
-{
- InitMenuClipRegion();
-}
-
-long MenuFloatingWindow::ImplGetStartY() const
-{
- long nY = 0;
- if( pMenu )
- {
- for ( sal_uInt16 n = 0; n < nFirstEntry; n++ )
- nY += pMenu->GetItemList()->GetDataFromPos( n )->aSz.Height();
- }
- return -nY;
-}
-
-Region MenuFloatingWindow::ImplCalcClipRegion( bool bIncludeLogo ) const
-{
- Size aOutSz = GetOutputSizePixel();
- Point aPos;
- Rectangle aRect( aPos, aOutSz );
- aRect.Top() += nScrollerHeight;
- aRect.Bottom() -= nScrollerHeight;
-
- if ( pMenu && pMenu->pLogo && !bIncludeLogo )
- aRect.Left() += pMenu->pLogo->aBitmap.GetSizePixel().Width();
-
- Region aRegion(aRect);
- if ( pMenu && pMenu->pLogo && bIncludeLogo && nScrollerHeight )
- aRegion.Union( Rectangle( Point(), Size( pMenu->pLogo->aBitmap.GetSizePixel().Width(), aOutSz.Height() ) ) );
-
- return aRegion;
-}
-
-void MenuFloatingWindow::InitMenuClipRegion()
-{
- if ( IsScrollMenu() )
- {
- SetClipRegion( ImplCalcClipRegion() );
- }
- else
- {
- SetClipRegion();
- }
-}
-
-void MenuFloatingWindow::ImplHighlightItem( const MouseEvent& rMEvt, bool bMBDown )
-{
- if( ! pMenu )
- return;
-
- long nY = nScrollerHeight + ImplGetSVData()->maNWFData.mnMenuFormatBorderY;
- long nMouseY = rMEvt.GetPosPixel().Y();
- Size aOutSz = GetOutputSizePixel();
- if ( ( nMouseY >= nY ) && ( nMouseY < ( aOutSz.Height() - nY ) ) )
- {
- bool bHighlighted = false;
- size_t nCount = pMenu->pItemList->size();
- nY += ImplGetStartY(); // ggf. gescrollt.
- for ( size_t n = 0; !bHighlighted && ( n < nCount ); n++ )
- {
- if ( pMenu->ImplIsVisible( n ) )
- {
- MenuItemData* pItemData = pMenu->pItemList->GetDataFromPos( n );
- long nOldY = nY;
- nY += pItemData->aSz.Height();
- if ( ( nOldY <= nMouseY ) && ( nY > nMouseY ) && pMenu->ImplIsSelectable( n ) )
- {
- bool bPopupArea = true;
- if ( pItemData->nBits & MIB_POPUPSELECT )
- {
- // only when clicked over the arrow...
- Size aSz = GetOutputSizePixel();
- long nFontHeight = GetTextHeight();
- bPopupArea = ( rMEvt.GetPosPixel().X() >= ( aSz.Width() - nFontHeight - nFontHeight/4 ) );
- }
-
- if ( bMBDown )
- {
- if ( n != nHighlightedItem )
- {
- ChangeHighlightItem( (sal_uInt16)n, false );
- }
-
- bool bAllowNewPopup = true;
- if ( pActivePopup )
- {
- MenuItemData* pData = pMenu->pItemList->GetDataFromPos( n );
- bAllowNewPopup = pData && ( pData->pSubMenu != pActivePopup );
- if ( bAllowNewPopup )
- KillActivePopup();
- }
-
- if ( bPopupArea && bAllowNewPopup )
- {
- HighlightChanged( NULL );
- }
- }
- else
- {
- if ( n != nHighlightedItem )
- {
- ChangeHighlightItem( (sal_uInt16)n, true );
- }
- else if ( pItemData->nBits & MIB_POPUPSELECT )
- {
- if ( bPopupArea && ( pActivePopup != pItemData->pSubMenu ) )
- HighlightChanged( NULL );
- }
- }
- bHighlighted = true;
- }
- }
- }
- if ( !bHighlighted )
- ChangeHighlightItem( ITEMPOS_INVALID, true );
- }
- else
- {
- ImplScroll( rMEvt.GetPosPixel() );
- ChangeHighlightItem( ITEMPOS_INVALID, true );
- }
-}
-
-IMPL_LINK_NOARG(MenuFloatingWindow, PopupEnd)
-{
- // "this" will be deleted before the end of this method!
- Menu* pM = pMenu;
- if ( bInExecute )
- {
- if ( pActivePopup )
- {
- //DBG_ASSERT( !pActivePopup->ImplGetWindow(), "PopupEnd, obwohl pActivePopup MIT Window!" );
- KillActivePopup(); // should be ok to just remove it
- //pActivePopup->bCanceled = true;
- }
- bInExecute = false;
- pMenu->bInCallback = true;
- pMenu->Deactivate();
- pMenu->bInCallback = false;
- }
- else
- {
- if( pMenu )
- {
- // if the window was closed by TH, there is another menu
- // which has this window as pActivePopup
- if ( pMenu->pStartedFrom )
- {
- // pWin from parent could be 0, if the list is
- // cleaned from the start, now clean up the endpopup-events
- if ( pMenu->pStartedFrom->bIsMenuBar )
- {
- MenuBarWindow* p = (MenuBarWindow*) pMenu->pStartedFrom->ImplGetWindow();
- if ( p )
- p->PopupClosed( pMenu );
- }
- else
- {
- MenuFloatingWindow* p = (MenuFloatingWindow*) pMenu->pStartedFrom->ImplGetWindow();
- if ( p )
- p->KillActivePopup( (PopupMenu*)pMenu );
- }
- }
- }
- }
-
- if ( pM )
- pM->pStartedFrom = 0;
-
- return 0;
-}
-
-IMPL_LINK_NOARG(MenuFloatingWindow, AutoScroll)
-{
- ImplScroll( GetPointerPosPixel() );
- return 1;
-}
-
-IMPL_LINK( MenuFloatingWindow, HighlightChanged, Timer*, pTimer )
-{
- if( ! pMenu )
- return 0;
-
- MenuItemData* pItemData = pMenu->pItemList->GetDataFromPos( nHighlightedItem );
- if ( pItemData )
- {
- if ( pActivePopup && ( pActivePopup != pItemData->pSubMenu ) )
- {
- sal_uLong nOldFlags = GetPopupModeFlags();
- SetPopupModeFlags( GetPopupModeFlags() | FLOATWIN_POPUPMODE_NOAPPFOCUSCLOSE );
- KillActivePopup();
- SetPopupModeFlags( nOldFlags );
- }
- if ( pItemData->bEnabled && pItemData->pSubMenu && pItemData->pSubMenu->GetItemCount() && ( pItemData->pSubMenu != pActivePopup ) )
- {
- pActivePopup = (PopupMenu*)pItemData->pSubMenu;
- long nY = nScrollerHeight+ImplGetStartY();
- MenuItemData* pData = 0;
- for ( sal_uLong n = 0; n < nHighlightedItem; n++ )
- {
- pData = pMenu->pItemList->GetDataFromPos( n );
- nY += pData->aSz.Height();
- }
- pData = pMenu->pItemList->GetDataFromPos( nHighlightedItem );
- Size MySize = GetOutputSizePixel();
- Point aItemTopLeft( 0, nY );
- Point aItemBottomRight( aItemTopLeft );
- aItemBottomRight.X() += MySize.Width();
- aItemBottomRight.Y() += pData->aSz.Height();
-
- // shift the popups a little
- aItemTopLeft.X() += 2;
- aItemBottomRight.X() -= 2;
- if ( nHighlightedItem )
- aItemTopLeft.Y() -= 2;
- else
- {
- sal_Int32 nL, nT, nR, nB;
- GetBorder( nL, nT, nR, nB );
- aItemTopLeft.Y() -= nT;
- }
-
- // pTest: crash due to Reschedule() in call of Activate()
- // Also it is prevented that submenus are displayed which
- // were for long in Activate Rescheduled and which should not be
- // displayed now.
- Menu* pTest = pActivePopup;
- sal_uLong nOldFlags = GetPopupModeFlags();
- SetPopupModeFlags( GetPopupModeFlags() | FLOATWIN_POPUPMODE_NOAPPFOCUSCLOSE );
- sal_uInt16 nRet = pActivePopup->ImplExecute( this, Rectangle( aItemTopLeft, aItemBottomRight ), FLOATWIN_POPUPMODE_RIGHT, pMenu, pTimer ? false : true );
- SetPopupModeFlags( nOldFlags );
-
- // nRet != 0, wenn es waerend Activate() abgeschossen wurde...
- if ( !nRet && ( pActivePopup == pTest ) && pActivePopup->ImplGetWindow() )
- pActivePopup->ImplGetFloatingWindow()->AddPopupModeWindow( this );
- }
- }
-
- return 0;
-}
-
-IMPL_LINK_NOARG(MenuFloatingWindow, SubmenuClose)
-{
- if( pMenu && pMenu->pStartedFrom )
- {
- MenuFloatingWindow* pWin = (MenuFloatingWindow*) pMenu->pStartedFrom->GetWindow();
- if( pWin )
- pWin->KillActivePopup();
- }
- return 0;
-}
-
-IMPL_LINK( MenuFloatingWindow, ShowHideListener, VclWindowEvent*, pEvent )
-{
- if( ! pMenu )
- return 0;
-
- if( pEvent->GetId() == VCLEVENT_WINDOW_SHOW )
- pMenu->ImplCallEventListeners( VCLEVENT_MENU_SHOW, ITEMPOS_INVALID );
- else if( pEvent->GetId() == VCLEVENT_WINDOW_HIDE )
- pMenu->ImplCallEventListeners( VCLEVENT_MENU_HIDE, ITEMPOS_INVALID );
- return 0;
-}
-
-void MenuFloatingWindow::EnableScrollMenu( bool b )
-{
- bScrollMenu = b;
- nScrollerHeight = b ? (sal_uInt16) GetSettings().GetStyleSettings().GetScrollBarSize() /2 : 0;
- bScrollDown = true;
- InitMenuClipRegion();
-}
-
-void MenuFloatingWindow::Execute()
-{
- ImplSVData* pSVData = ImplGetSVData();
-
- pSVData->maAppData.mpActivePopupMenu = (PopupMenu*)pMenu;
-
- bInExecute = true;
-// bCallingSelect = false;
-
- while ( bInExecute )
- Application::Yield();
-
- pSVData->maAppData.mpActivePopupMenu = NULL;
-}
-
-void MenuFloatingWindow::StopExecute( sal_uLong nFocusId )
-{
- // restore focus
- // (could have been restored in Select)
- if ( nSaveFocusId )
- {
- Window::EndSaveFocus( nFocusId, false );
- nFocusId = nSaveFocusId;
- if ( nFocusId )
- {
- nSaveFocusId = 0;
- ImplGetSVData()->maWinData.mbNoDeactivate = false;
- }
- }
- ImplEndPopupMode( 0, nFocusId );
-
- aHighlightChangedTimer.Stop();
- bInExecute = false;
- if ( pActivePopup )
- {
- KillActivePopup();
- }
- // notify parent, needed for accessibility
- if( pMenu && pMenu->pStartedFrom )
- pMenu->pStartedFrom->ImplCallEventListeners( VCLEVENT_MENU_SUBMENUDEACTIVATE, nPosInParent );
-}
-
-void MenuFloatingWindow::KillActivePopup( PopupMenu* pThisOnly )
-{
- if ( pActivePopup && ( !pThisOnly || ( pThisOnly == pActivePopup ) ) )
- {
- if( pActivePopup->pWindow != NULL )
- if( ((FloatingWindow *) pActivePopup->pWindow)->IsInCleanUp() )
- return; // kill it later
- if ( pActivePopup->bInCallback )
- pActivePopup->bCanceled = true;
-
- // For all actions pActivePopup = 0, if e.g.
- // PopupModeEndHdl the popups to destroy were called synchronous
- PopupMenu* pPopup = pActivePopup;
- pActivePopup = NULL;
- pPopup->bInCallback = true;
- pPopup->Deactivate();
- pPopup->bInCallback = false;
- if ( pPopup->ImplGetWindow() )
- {
- pPopup->ImplGetFloatingWindow()->StopExecute();
- pPopup->ImplGetFloatingWindow()->doShutdown();
- pPopup->pWindow->doLazyDelete();
- pPopup->pWindow = NULL;
-
- Update();
- }
- }
-}
-
-void MenuFloatingWindow::EndExecute()
-{
- Menu* pStart = pMenu ? pMenu->ImplGetStartMenu() : NULL;
- sal_uLong nFocusId = 0;
- if ( pStart && pStart->bIsMenuBar )
- {
- nFocusId = ((MenuBarWindow*)((MenuBar*)pStart)->ImplGetWindow())->GetFocusId();
- if ( nFocusId )
- {
- ((MenuBarWindow*)((MenuBar*)pStart)->ImplGetWindow())->SetFocusId( 0 );
- ImplGetSVData()->maWinData.mbNoDeactivate = false;
- }
- }
-
- // if started else where, cleanup there as well
- MenuFloatingWindow* pCleanUpFrom = this;
- MenuFloatingWindow* pWin = this;
- while ( pWin && !pWin->bInExecute &&
- pWin->pMenu->pStartedFrom && !pWin->pMenu->pStartedFrom->bIsMenuBar )
- {
- pWin = ((PopupMenu*)pWin->pMenu->pStartedFrom)->ImplGetFloatingWindow();
- }
- if ( pWin )
- pCleanUpFrom = pWin;
-
- // this window will be destroyed => store date locally...
- Menu* pM = pMenu;
- sal_uInt16 nItem = nHighlightedItem;
-
- pCleanUpFrom->StopExecute( nFocusId );
-
- if ( nItem != ITEMPOS_INVALID && pM )
- {
- MenuItemData* pItemData = pM->GetItemList()->GetDataFromPos( nItem );
- if ( pItemData && !pItemData->bIsTemporary )
- {
- pM->nSelectedId = pItemData->nId;
- if ( pStart )
- pStart->nSelectedId = pItemData->nId;
-
- pM->ImplSelect();
- }
- }
-}
-
-void MenuFloatingWindow::EndExecute( sal_uInt16 nId )
-{
- size_t nPos;
- if ( pMenu && pMenu->GetItemList()->GetData( nId, nPos ) )
- nHighlightedItem = nPos;
- else
- nHighlightedItem = ITEMPOS_INVALID;
-
- EndExecute();
-}
-
-void MenuFloatingWindow::MouseButtonDown( const MouseEvent& rMEvt )
-{
- // TH creates a ToTop on this window, but the active popup
- // should stay on top...
- // due to focus change this would close all menus -> don't do it (#94123)
- //if ( pActivePopup && pActivePopup->ImplGetWindow() && !pActivePopup->ImplGetFloatingWindow()->pActivePopup )
- // pActivePopup->ImplGetFloatingWindow()->ToTop( TOTOP_NOGRABFOCUS );
-
- ImplHighlightItem( rMEvt, true );
-
- nMBDownPos = nHighlightedItem;
-}
-
-void MenuFloatingWindow::MouseButtonUp( const MouseEvent& rMEvt )
-{
- MenuItemData* pData = pMenu ? pMenu->GetItemList()->GetDataFromPos( nHighlightedItem ) : NULL;
- // nMBDownPos store in local variable and reset immediately,
- // as it will be too late after EndExecute
- sal_uInt16 _nMBDownPos = nMBDownPos;
- nMBDownPos = ITEMPOS_INVALID;
- if ( pData && pData->bEnabled && ( pData->eType != MENUITEM_SEPARATOR ) )
- {
- if ( !pData->pSubMenu )
- {
- EndExecute();
- }
- else if ( ( pData->nBits & MIB_POPUPSELECT ) && ( nHighlightedItem == _nMBDownPos ) && ( rMEvt.GetClicks() == 2 ) )
- {
- // not when clicked over the arrow...
- Size aSz = GetOutputSizePixel();
- long nFontHeight = GetTextHeight();
- if ( rMEvt.GetPosPixel().X() < ( aSz.Width() - nFontHeight - nFontHeight/4 ) )
- EndExecute();
- }
- }
-
-}
-
-void MenuFloatingWindow::MouseMove( const MouseEvent& rMEvt )
-{
- if ( !IsVisible() || rMEvt.IsSynthetic() || rMEvt.IsEnterWindow() )
- return;
-
- if ( rMEvt.IsLeaveWindow() )
- {
- // #102461# do not remove highlight if a popup menu is open at this position
- MenuItemData* pData = pMenu ? pMenu->pItemList->GetDataFromPos( nHighlightedItem ) : NULL;
- // close popup with some delayed if we leave somewhere else
- if( pActivePopup && pData && pData->pSubMenu != pActivePopup )
- pActivePopup->ImplGetFloatingWindow()->aSubmenuCloseTimer.Start();
-
- if( !pActivePopup || (pData && pData->pSubMenu != pActivePopup ) )
- ChangeHighlightItem( ITEMPOS_INVALID, false );
-
- if ( IsScrollMenu() )
- ImplScroll( rMEvt.GetPosPixel() );
- }
- else
- {
- aSubmenuCloseTimer.Stop();
- if( bIgnoreFirstMove )
- bIgnoreFirstMove = false;
- else
- ImplHighlightItem( rMEvt, false );
- }
-}
-
-void MenuFloatingWindow::ImplScroll( bool bUp )
-{
- KillActivePopup();
- Update();
-
- if( ! pMenu )
- return;
-
- HighlightItem( nHighlightedItem, false );
-
- pMenu->ImplKillLayoutData();
-
- if ( bScrollUp && bUp )
- {
- nFirstEntry = pMenu->ImplGetPrevVisible( nFirstEntry );
- DBG_ASSERT( nFirstEntry != ITEMPOS_INVALID, "Scroll?!" );
-
- long nScrollEntryHeight = pMenu->GetItemList()->GetDataFromPos( nFirstEntry )->aSz.Height();
-
- if ( !bScrollDown )
- {
- bScrollDown = true;
- ImplDrawScroller( false );
- }
-
- if ( pMenu->ImplGetPrevVisible( nFirstEntry ) == ITEMPOS_INVALID )
- {
- bScrollUp = false;
- ImplDrawScroller( true );
- }
-
- Scroll( 0, nScrollEntryHeight, ImplCalcClipRegion( false ).GetBoundRect(), SCROLL_CLIP );
- }
- else if ( bScrollDown && !bUp )
- {
- long nScrollEntryHeight = pMenu->GetItemList()->GetDataFromPos( nFirstEntry )->aSz.Height();
-
- nFirstEntry = pMenu->ImplGetNextVisible( nFirstEntry );
- DBG_ASSERT( nFirstEntry != ITEMPOS_INVALID, "Scroll?!" );
-
- if ( !bScrollUp )
- {
- bScrollUp = true;
- ImplDrawScroller( true );
- }
-
- long nHeight = GetOutputSizePixel().Height();
- sal_uInt16 nLastVisible;
- ((PopupMenu*)pMenu)->ImplCalcVisEntries( nHeight, nFirstEntry, &nLastVisible );
- if ( pMenu->ImplGetNextVisible( nLastVisible ) == ITEMPOS_INVALID )
- {
- bScrollDown = false;
- ImplDrawScroller( false );
- }
-
- Scroll( 0, -nScrollEntryHeight, ImplCalcClipRegion( false ).GetBoundRect(), SCROLL_CLIP );
- }
-
- HighlightItem( nHighlightedItem, true );
-}
-
-void MenuFloatingWindow::ImplScroll( const Point& rMousePos )
-{
- Size aOutSz = GetOutputSizePixel();
-
- long nY = nScrollerHeight;
- long nMouseY = rMousePos.Y();
- long nDelta = 0;
-
- if ( bScrollUp && ( nMouseY < nY ) )
- {
- ImplScroll( true );
- nDelta = nY - nMouseY;
- }
- else if ( bScrollDown && ( nMouseY > ( aOutSz.Height() - nY ) ) )
- {
- ImplScroll( false );
- nDelta = nMouseY - ( aOutSz.Height() - nY );
- }
-
- if ( nDelta )
- {
- aScrollTimer.Stop(); // if scrolled through MouseMove.
- long nTimeout;
- if ( nDelta < 3 )
- nTimeout = 200;
- else if ( nDelta < 5 )
- nTimeout = 100;
- else if ( nDelta < 8 )
- nTimeout = 70;
- else if ( nDelta < 12 )
- nTimeout = 40;
- else
- nTimeout = 20;
- aScrollTimer.SetTimeout( nTimeout );
- aScrollTimer.Start();
- }
-}
-void MenuFloatingWindow::ChangeHighlightItem( sal_uInt16 n, bool bStartPopupTimer )
-{
- // #57934# ggf. immediately close the active, as TH's backgroundstorage works.
- // #65750# we prefer to refrain from the background storage of small lines.
- // otherwise the menus are difficult to operate.
- // MenuItemData* pNextData = pMenu->pItemList->GetDataFromPos( n );
- // if ( pActivePopup && pNextData && ( pActivePopup != pNextData->pSubMenu ) )
- // KillActivePopup();
-
- aSubmenuCloseTimer.Stop();
- if( ! pMenu )
- return;
-
- if ( nHighlightedItem != ITEMPOS_INVALID )
- {
- HighlightItem( nHighlightedItem, false );
- pMenu->ImplCallEventListeners( VCLEVENT_MENU_DEHIGHLIGHT, nHighlightedItem );
- }
-
- nHighlightedItem = (sal_uInt16)n;
- DBG_ASSERT( pMenu->ImplIsVisible( nHighlightedItem ) || nHighlightedItem == ITEMPOS_INVALID, "ChangeHighlightItem: Not visible!" );
- if( nHighlightedItem != ITEMPOS_INVALID )
- {
- if( pMenu->pStartedFrom && !pMenu->pStartedFrom->bIsMenuBar )
- {
- // #102461# make sure parent entry is highlighted as well
- MenuItemData* pData;
- size_t i, nCount = pMenu->pStartedFrom->pItemList->size();
- for(i = 0; i < nCount; i++)
- {
- pData = pMenu->pStartedFrom->pItemList->GetDataFromPos( i );
- if( pData && ( pData->pSubMenu == pMenu ) )
- break;
- }
- if( i < nCount )
- {
- MenuFloatingWindow* pPWin = (MenuFloatingWindow*)pMenu->pStartedFrom->ImplGetWindow();
- if( pPWin && pPWin->nHighlightedItem != i )
- {
- pPWin->HighlightItem( i, true );
- pPWin->nHighlightedItem = i;
- }
- }
- }
- HighlightItem( nHighlightedItem, true );
- pMenu->SetHighlightItem(nHighlightedItem);
- pMenu->ImplCallHighlight( nHighlightedItem );
- }
- else
- pMenu->nSelectedId = 0;
-
- if ( bStartPopupTimer )
- {
- // #102438# Menu items are not selectable
- // If a menu item is selected by an AT-tool via the XAccessibleAction, XAccessibleValue
- // or XAccessibleSelection interface, and the parent popup menus are not executed yet,
- // the parent popup menus must be executed SYNCHRONOUSLY, before the menu item is selected.
- if ( GetSettings().GetMouseSettings().GetMenuDelay() )
- aHighlightChangedTimer.Start();
- else
- HighlightChanged( &aHighlightChangedTimer );
- }
-}
-
-void MenuFloatingWindow::HighlightItem( sal_uInt16 nPos, bool bHighlight )
-{
- if( ! pMenu )
- return;
-
- Size aSz = GetOutputSizePixel();
- long nStartY = ImplGetStartY();
- long nY = nScrollerHeight + nStartY + ImplGetSVData()->maNWFData.mnMenuFormatBorderY;
- long nX = 0;
-
- if ( pMenu->pLogo )
- nX = pMenu->pLogo->aBitmap.GetSizePixel().Width();
-
- int nOuterSpaceX = ImplGetSVData()->maNWFData.mnMenuFormatBorderX;
-
- size_t nCount = pMenu->pItemList->size();
- for ( size_t n = 0; n < nCount; n++ )
- {
- MenuItemData* pData = pMenu->pItemList->GetDataFromPos( n );
- if ( n == nPos )
- {
- DBG_ASSERT( pMenu->ImplIsVisible( n ), "Highlight: Item not visible!" );
- if ( pData->eType != MENUITEM_SEPARATOR )
- {
- bool bRestoreLineColor = false;
- Color oldLineColor;
- bool bDrawItemRect = true;
-
- Rectangle aItemRect( Point( nX+nOuterSpaceX, nY ), Size( aSz.Width()-2*nOuterSpaceX, pData->aSz.Height() ) );
- if ( pData->nBits & MIB_POPUPSELECT )
- {
- long nFontHeight = GetTextHeight();
- aItemRect.Right() -= nFontHeight + nFontHeight/4;
- }
-
- if( IsNativeControlSupported( CTRL_MENU_POPUP, PART_ENTIRE_CONTROL ) )
- {
- Size aPxSize( GetOutputSizePixel() );
- Push( PUSH_CLIPREGION );
- IntersectClipRegion( Rectangle( Point( nX, nY ), Size( aSz.Width(), pData->aSz.Height() ) ) );
- Rectangle aCtrlRect( Point( nX, 0 ), Size( aPxSize.Width()-nX, aPxSize.Height() ) );
- MenupopupValue aVal( pMenu->nTextPos-GUTTERBORDER, aItemRect );
- DrawNativeControl( CTRL_MENU_POPUP, PART_ENTIRE_CONTROL,
- aCtrlRect,
- CTRL_STATE_ENABLED,
- aVal,
- OUString() );
- if( bHighlight &&
- IsNativeControlSupported( CTRL_MENU_POPUP, PART_MENU_ITEM ) )
- {
- bDrawItemRect = false;
- if( !DrawNativeControl( CTRL_MENU_POPUP, PART_MENU_ITEM,
- aItemRect,
- CTRL_STATE_SELECTED | ( pData->bEnabled? CTRL_STATE_ENABLED: 0 ),
- aVal,
- OUString() ) )
- {
- bDrawItemRect = bHighlight;
- }
- }
- else
- bDrawItemRect = bHighlight;
- Pop();
- }
- if( bDrawItemRect )
- {
- if ( bHighlight )
- {
- if( pData->bEnabled )
- SetFillColor( GetSettings().GetStyleSettings().GetMenuHighlightColor() );
- else
- {
- SetFillColor();
- oldLineColor = GetLineColor();
- SetLineColor( GetSettings().GetStyleSettings().GetMenuHighlightColor() );
- bRestoreLineColor = true;
- }
- }
- else
- SetFillColor( GetSettings().GetStyleSettings().GetMenuColor() );
-
- DrawRect( aItemRect );
- }
- pMenu->ImplPaint( this, nScrollerHeight, nStartY, pData, bHighlight );
- if( bRestoreLineColor )
- SetLineColor( oldLineColor );
- }
- return;
- }
-
- nY += pData->aSz.Height();
- }
-}
-
-Rectangle MenuFloatingWindow::ImplGetItemRect( sal_uInt16 nPos )
-{
- if( ! pMenu )
- return Rectangle();
-
- Rectangle aRect;
- Size aSz = GetOutputSizePixel();
- long nStartY = ImplGetStartY();
- long nY = nScrollerHeight+nStartY;
- long nX = 0;
-
- if ( pMenu->pLogo )
- nX = pMenu->pLogo->aBitmap.GetSizePixel().Width();
-
- size_t nCount = pMenu->pItemList->size();
- for ( size_t n = 0; n < nCount; n++ )
- {
- MenuItemData* pData = pMenu->pItemList->GetDataFromPos( n );
- if ( n == nPos )
- {
- DBG_ASSERT( pMenu->ImplIsVisible( n ), "ImplGetItemRect: Item not visible!" );
- if ( pData->eType != MENUITEM_SEPARATOR )
- {
- aRect = Rectangle( Point( nX, nY ), Size( aSz.Width(), pData->aSz.Height() ) );
- if ( pData->nBits & MIB_POPUPSELECT )
- {
- long nFontHeight = GetTextHeight();
- aRect.Right() -= nFontHeight + nFontHeight/4;
- }
- }
- break;
- }
- nY += pData->aSz.Height();
- }
- return aRect;
-}
-
-void MenuFloatingWindow::ImplCursorUpDown( bool bUp, bool bHomeEnd )
-{
- if( ! pMenu )
- return;
-
- const StyleSettings& rSettings = GetSettings().GetStyleSettings();
-
- sal_uInt16 n = nHighlightedItem;
- if ( n == ITEMPOS_INVALID )
- {
- if ( bUp )
- n = 0;
- else
- n = pMenu->GetItemCount()-1;
- }
-
- sal_uInt16 nLoop = n;
-
- if( bHomeEnd )
- {
- // absolute positioning
- if( bUp )
- {
- n = pMenu->GetItemCount();
- nLoop = n-1;
- }
- else
- {
- n = (sal_uInt16)-1;
- nLoop = n+1;
- }
- }
-
- do
- {
- if ( bUp )
- {
- if ( n )
- n--;
- else
- if ( !IsScrollMenu() || ( nHighlightedItem == ITEMPOS_INVALID ) )
- n = pMenu->GetItemCount()-1;
- else
- break;
- }
- else
- {
- n++;
- if ( n >= pMenu->GetItemCount() )
- {
- if ( !IsScrollMenu() || ( nHighlightedItem == ITEMPOS_INVALID ) )
- n = 0;
- else
- break;
- }
- }
-
- MenuItemData* pData = (MenuItemData*)pMenu->GetItemList()->GetDataFromPos( n );
- if ( ( pData->bEnabled || !rSettings.GetSkipDisabledInMenus() )
- && ( pData->eType != MENUITEM_SEPARATOR ) && pMenu->ImplIsVisible( n ) && pMenu->ImplIsSelectable( n ) )
- {
- // Is selection in visible area?
- if ( IsScrollMenu() )
- {
- ChangeHighlightItem( ITEMPOS_INVALID, false );
-
- while ( n < nFirstEntry )
- ImplScroll( true );
-
- Size aOutSz = GetOutputSizePixel();
- sal_uInt16 nLastVisible;
- ((PopupMenu*)pMenu)->ImplCalcVisEntries( aOutSz.Height(), nFirstEntry, &nLastVisible );
- while ( n > nLastVisible )
- {
- ImplScroll( false );
- ((PopupMenu*)pMenu)->ImplCalcVisEntries( aOutSz.Height(), nFirstEntry, &nLastVisible );
- }
- }
- ChangeHighlightItem( n, false );
- break;
- }
- } while ( n != nLoop );
-}
-
-void MenuFloatingWindow::KeyInput( const KeyEvent& rKEvent )
-{
- ImplDelData aDelData;
- ImplAddDel( &aDelData );
-
- sal_uInt16 nCode = rKEvent.GetKeyCode().GetCode();
- bKeyInput = true;
- switch ( nCode )
- {
- case KEY_UP:
- case KEY_DOWN:
- {
- ImplCursorUpDown( nCode == KEY_UP );
- }
- break;
- case KEY_END:
- case KEY_HOME:
- {
- ImplCursorUpDown( nCode == KEY_END, true );
- }
- break;
- case KEY_F6:
- case KEY_ESCAPE:
- {
- // Ctrl-F6 acts like ESC here, the menu bar however will then put the focus in the document
- if( nCode == KEY_F6 && !rKEvent.GetKeyCode().IsMod1() )
- break;
- if( pMenu )
- {
- if ( !pMenu->pStartedFrom )
- {
- StopExecute();
- KillActivePopup();
- }
- else if ( pMenu->pStartedFrom->bIsMenuBar )
- {
- // Forward...
- ((MenuBarWindow*)((MenuBar*)pMenu->pStartedFrom)->ImplGetWindow())->KeyInput( rKEvent );
- }
- else
- {
- StopExecute();
- PopupMenu* pPopupMenu = (PopupMenu*)pMenu->pStartedFrom;
- MenuFloatingWindow* pFloat = pPopupMenu->ImplGetFloatingWindow();
- pFloat->GrabFocus();
- pFloat->KillActivePopup();
- pPopupMenu->ImplCallHighlight(pFloat->nHighlightedItem);
- }
- }
- }
- break;
- case KEY_LEFT:
- {
- if ( pMenu && pMenu->pStartedFrom )
- {
- StopExecute();
- if ( pMenu->pStartedFrom->bIsMenuBar )
- {
- // Forward...
- ((MenuBarWindow*)((MenuBar*)pMenu->pStartedFrom)->ImplGetWindow())->KeyInput( rKEvent );
- }
- else
- {
- MenuFloatingWindow* pFloat = ((PopupMenu*)pMenu->pStartedFrom)->ImplGetFloatingWindow();
- pFloat->GrabFocus();
- pFloat->KillActivePopup();
- sal_uInt16 highlightItem = pFloat->GetHighlightedItem();
- pFloat->ChangeHighlightItem(highlightItem, false);
- }
- }
- }
- break;
- case KEY_RIGHT:
- {
- if( pMenu )
- {
- bool bDone = false;
- if ( nHighlightedItem != ITEMPOS_INVALID )
- {
- MenuItemData* pData = pMenu->GetItemList()->GetDataFromPos( nHighlightedItem );
- if ( pData && pData->pSubMenu )
- {
- HighlightChanged( 0 );
- bDone = true;
- }
- }
- if ( !bDone )
- {
- Menu* pStart = pMenu->ImplGetStartMenu();
- if ( pStart && pStart->bIsMenuBar )
- {
- // Forward...
- pStart->ImplGetWindow()->KeyInput( rKEvent );
- }
- }
- }
- }
- break;
- case KEY_RETURN:
- {
- if( pMenu )
- {
- MenuItemData* pData = pMenu->GetItemList()->GetDataFromPos( nHighlightedItem );
- if ( pData && pData->bEnabled )
- {
- if ( pData->pSubMenu )
- HighlightChanged( 0 );
- else
- EndExecute();
- }
- else
- StopExecute();
- }
- }
- break;
- case KEY_MENU:
- {
- if( pMenu )
- {
- Menu* pStart = pMenu->ImplGetStartMenu();
- if ( pStart && pStart->bIsMenuBar )
- {
- // Forward...
- pStart->ImplGetWindow()->KeyInput( rKEvent );
- }
- }
- }
- break;
- default:
- {
- sal_Unicode nCharCode = rKEvent.GetCharCode();
- sal_uInt16 nPos = 0;
- sal_uInt16 nDuplicates = 0;
- MenuItemData* pData = (nCharCode && pMenu) ? pMenu->GetItemList()->SearchItem( nCharCode, rKEvent.GetKeyCode(), nPos, nDuplicates, nHighlightedItem ) : NULL;
- if ( pData )
- {
- if ( pData->pSubMenu || nDuplicates > 1 )
- {
- ChangeHighlightItem( nPos, false );
- HighlightChanged( 0 );
- }
- else
- {
- nHighlightedItem = nPos;
- EndExecute();
- }
- }
- else
- FloatingWindow::KeyInput( rKEvent );
- }
- }
- // #105474# check if menu window was not destroyed
- if ( !aDelData.IsDead() )
- {
- ImplRemoveDel( &aDelData );
- bKeyInput = false;
- }
-}
-
-void MenuFloatingWindow::Paint( const Rectangle& )
-{
- if( ! pMenu )
- return;
-
- if( IsNativeControlSupported( CTRL_MENU_POPUP, PART_ENTIRE_CONTROL ) )
- {
- SetClipRegion();
- long nX = pMenu->pLogo ? pMenu->pLogo->aBitmap.GetSizePixel().Width() : 0;
- Size aPxSize( GetOutputSizePixel() );
- aPxSize.Width() -= nX;
- ImplControlValue aVal( pMenu->nTextPos-GUTTERBORDER );
- DrawNativeControl( CTRL_MENU_POPUP, PART_ENTIRE_CONTROL,
- Rectangle( Point( nX, 0 ), aPxSize ),
- CTRL_STATE_ENABLED,
- aVal,
- OUString() );
- InitMenuClipRegion();
- }
- if ( IsScrollMenu() )
- {
- ImplDrawScroller( true );
- ImplDrawScroller( false );
- }
- SetFillColor( GetSettings().GetStyleSettings().GetMenuColor() );
- pMenu->ImplPaint( this, nScrollerHeight, ImplGetStartY() );
- if ( nHighlightedItem != ITEMPOS_INVALID )
- HighlightItem( nHighlightedItem, true );
-}
-
-void MenuFloatingWindow::ImplDrawScroller( bool bUp )
-{
- if( ! pMenu )
- return;
-
- SetClipRegion();
-
- Size aOutSz = GetOutputSizePixel();
- long nY = bUp ? 0 : ( aOutSz.Height() - nScrollerHeight );
- long nX = pMenu->pLogo ? pMenu->pLogo->aBitmap.GetSizePixel().Width() : 0;
- Rectangle aRect( Point( nX, nY ), Size( aOutSz.Width()-nX, nScrollerHeight ) );
-
- DecorationView aDecoView( this );
- SymbolType eSymbol = bUp ? SYMBOL_SPIN_UP : SYMBOL_SPIN_DOWN;
-
- sal_uInt16 nStyle = 0;
- if ( ( bUp && !bScrollUp ) || ( !bUp && !bScrollDown ) )
- nStyle |= SYMBOL_DRAW_DISABLE;
-
- aDecoView.DrawSymbol( aRect, eSymbol, GetSettings().GetStyleSettings().GetButtonTextColor(), nStyle );
-
- InitMenuClipRegion();
-}
-
-void MenuFloatingWindow::RequestHelp( const HelpEvent& rHEvt )
-{
- sal_uInt16 nId = nHighlightedItem;
- Menu* pM = pMenu;
- Window* pW = this;
-
- // #102618# Get item rect before destroying the window in EndExecute() call
- Rectangle aHighlightRect( ImplGetItemRect( nHighlightedItem ) );
-
- if ( rHEvt.GetMode() & (HELPMODE_CONTEXT | HELPMODE_EXTENDED) )
- {
- nHighlightedItem = ITEMPOS_INVALID;
- EndExecute();
- pW = NULL;
- }
-
- if( !ImplHandleHelpEvent( pW, pM, nId, rHEvt, aHighlightRect ) )
- Window::RequestHelp( rHEvt );
-}
-
-void MenuFloatingWindow::StateChanged( StateChangedType nType )
-{
- FloatingWindow::StateChanged( nType );
-
- if ( ( nType == STATE_CHANGE_CONTROLFOREGROUND ) || ( nType == STATE_CHANGE_CONTROLBACKGROUND ) )
- {
- ImplInitMenuWindow( this, false, false );
- Invalidate();
- }
-}
-
-void MenuFloatingWindow::DataChanged( const DataChangedEvent& rDCEvt )
-{
- FloatingWindow::DataChanged( rDCEvt );
-
- if ( (rDCEvt.GetType() == DATACHANGED_FONTS) ||
- (rDCEvt.GetType() == DATACHANGED_FONTSUBSTITUTION) ||
- ((rDCEvt.GetType() == DATACHANGED_SETTINGS) &&
- (rDCEvt.GetFlags() & SETTINGS_STYLE)) )
- {
- ImplInitMenuWindow( this, false, false );
- Invalidate();
- }
-}
-
-void MenuFloatingWindow::Command( const CommandEvent& rCEvt )
-{
- if ( rCEvt.GetCommand() == COMMAND_WHEEL )
- {
- const CommandWheelData* pData = rCEvt.GetWheelData();
- if( !pData->GetModifier() && ( pData->GetMode() == COMMAND_WHEEL_SCROLL ) )
- {
-// ImplCursorUpDown( pData->GetDelta() > 0L );
- ImplScroll( pData->GetDelta() > 0L );
- MouseMove( MouseEvent( GetPointerPosPixel(), 0 ) );
- }
- }
-}
-
-::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible > MenuFloatingWindow::CreateAccessible()
-{
- ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible > xAcc;
-
- if ( pMenu && !pMenu->pStartedFrom )
- xAcc = pMenu->GetAccessible();
-
- return xAcc;
-}
-
MenuBarWindow::MenuBarWindow( Window* pParent ) :
Window( pParent, 0 ),
aCloser( this ),
diff --git a/vcl/source/window/menufloatingwindow.cxx b/vcl/source/window/menufloatingwindow.cxx
new file mode 100644
index 000000000000..6359606f39a2
--- /dev/null
+++ b/vcl/source/window/menufloatingwindow.cxx
@@ -0,0 +1,1209 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "menufloatingwindow.hxx"
+#include "menuitemlist.hxx"
+
+#include <svdata.hxx>
+#include <vcl/decoview.hxx>
+#include <vcl/settings.hxx>
+#include <window.h>
+
+MenuFloatingWindow::MenuFloatingWindow( Menu* pMen, Window* pParent, WinBits nStyle ) :
+ FloatingWindow( pParent, nStyle )
+{
+ mpWindowImpl->mbMenuFloatingWindow= true;
+ pMenu = pMen;
+ pActivePopup = 0;
+ nSaveFocusId = 0;
+ bInExecute = false;
+ bScrollMenu = false;
+ nHighlightedItem = ITEMPOS_INVALID;
+ nMBDownPos = ITEMPOS_INVALID;
+ nPosInParent = ITEMPOS_INVALID;
+ nScrollerHeight = 0;
+ nBorder = EXTRASPACEY;
+ nFirstEntry = 0;
+ bScrollUp = false;
+ bScrollDown = false;
+ bIgnoreFirstMove = true;
+ bKeyInput = false;
+
+ EnableSaveBackground();
+ ImplInitMenuWindow( this, true, false );
+
+ SetPopupModeEndHdl( LINK( this, MenuFloatingWindow, PopupEnd ) );
+
+ aHighlightChangedTimer.SetTimeoutHdl( LINK( this, MenuFloatingWindow, HighlightChanged ) );
+ aHighlightChangedTimer.SetTimeout( GetSettings().GetMouseSettings().GetMenuDelay() );
+ aSubmenuCloseTimer.SetTimeout( GetSettings().GetMouseSettings().GetMenuDelay() );
+ aSubmenuCloseTimer.SetTimeoutHdl( LINK( this, MenuFloatingWindow, SubmenuClose ) );
+ aScrollTimer.SetTimeoutHdl( LINK( this, MenuFloatingWindow, AutoScroll ) );
+
+ AddEventListener( LINK( this, MenuFloatingWindow, ShowHideListener ) );
+}
+
+void MenuFloatingWindow::doShutdown()
+{
+ if( pMenu )
+ {
+ // #105373# notify toolkit that highlight was removed
+ // otherwise the entry will not be read when the menu is opened again
+ if( nHighlightedItem != ITEMPOS_INVALID )
+ pMenu->ImplCallEventListeners( VCLEVENT_MENU_DEHIGHLIGHT, nHighlightedItem );
+ pMenu->SetHighlightItem(ITEMPOS_INVALID);
+ if( !bKeyInput && pMenu && pMenu->pStartedFrom && !pMenu->pStartedFrom->bIsMenuBar )
+ {
+ // #102461# remove highlight in parent
+ MenuItemData* pData;
+ size_t i, nCount = pMenu->pStartedFrom->pItemList->size();
+ for(i = 0; i < nCount; i++)
+ {
+ pData = pMenu->pStartedFrom->pItemList->GetDataFromPos( i );
+ if( pData && ( pData->pSubMenu == pMenu ) )
+ break;
+ }
+ if( i < nCount )
+ {
+ MenuFloatingWindow* pPWin = (MenuFloatingWindow*)pMenu->pStartedFrom->ImplGetWindow();
+ if( pPWin )
+ pPWin->HighlightItem( i, false );
+ }
+ }
+
+ // free the reference to the accessible component
+ SetAccessible( ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible >() );
+
+ aHighlightChangedTimer.Stop();
+
+ // #95056# invalidate screen area covered by system window
+ // so this can be taken into account if the commandhandler performs a scroll operation
+ if( GetParent() )
+ {
+ Rectangle aInvRect( GetWindowExtentsRelative( GetParent() ) );
+ GetParent()->Invalidate( aInvRect );
+ }
+ pMenu = NULL;
+ RemoveEventListener( LINK( this, MenuFloatingWindow, ShowHideListener ) );
+ }
+}
+
+MenuFloatingWindow::~MenuFloatingWindow()
+{
+ doShutdown();
+}
+
+void MenuFloatingWindow::Resize()
+{
+ InitMenuClipRegion();
+}
+
+long MenuFloatingWindow::ImplGetStartY() const
+{
+ long nY = 0;
+ if( pMenu )
+ {
+ for ( sal_uInt16 n = 0; n < nFirstEntry; n++ )
+ nY += pMenu->GetItemList()->GetDataFromPos( n )->aSz.Height();
+ }
+ return -nY;
+}
+
+Region MenuFloatingWindow::ImplCalcClipRegion( bool bIncludeLogo ) const
+{
+ Size aOutSz = GetOutputSizePixel();
+ Point aPos;
+ Rectangle aRect( aPos, aOutSz );
+ aRect.Top() += nScrollerHeight;
+ aRect.Bottom() -= nScrollerHeight;
+
+ if ( pMenu && pMenu->pLogo && !bIncludeLogo )
+ aRect.Left() += pMenu->pLogo->aBitmap.GetSizePixel().Width();
+
+ Region aRegion(aRect);
+ if ( pMenu && pMenu->pLogo && bIncludeLogo && nScrollerHeight )
+ aRegion.Union( Rectangle( Point(), Size( pMenu->pLogo->aBitmap.GetSizePixel().Width(), aOutSz.Height() ) ) );
+
+ return aRegion;
+}
+
+void MenuFloatingWindow::InitMenuClipRegion()
+{
+ if ( IsScrollMenu() )
+ {
+ SetClipRegion( ImplCalcClipRegion() );
+ }
+ else
+ {
+ SetClipRegion();
+ }
+}
+
+void MenuFloatingWindow::ImplHighlightItem( const MouseEvent& rMEvt, bool bMBDown )
+{
+ if( ! pMenu )
+ return;
+
+ long nY = nScrollerHeight + ImplGetSVData()->maNWFData.mnMenuFormatBorderY;
+ long nMouseY = rMEvt.GetPosPixel().Y();
+ Size aOutSz = GetOutputSizePixel();
+ if ( ( nMouseY >= nY ) && ( nMouseY < ( aOutSz.Height() - nY ) ) )
+ {
+ bool bHighlighted = false;
+ size_t nCount = pMenu->pItemList->size();
+ nY += ImplGetStartY(); // ggf. gescrollt.
+ for ( size_t n = 0; !bHighlighted && ( n < nCount ); n++ )
+ {
+ if ( pMenu->ImplIsVisible( n ) )
+ {
+ MenuItemData* pItemData = pMenu->pItemList->GetDataFromPos( n );
+ long nOldY = nY;
+ nY += pItemData->aSz.Height();
+ if ( ( nOldY <= nMouseY ) && ( nY > nMouseY ) && pMenu->ImplIsSelectable( n ) )
+ {
+ bool bPopupArea = true;
+ if ( pItemData->nBits & MIB_POPUPSELECT )
+ {
+ // only when clicked over the arrow...
+ Size aSz = GetOutputSizePixel();
+ long nFontHeight = GetTextHeight();
+ bPopupArea = ( rMEvt.GetPosPixel().X() >= ( aSz.Width() - nFontHeight - nFontHeight/4 ) );
+ }
+
+ if ( bMBDown )
+ {
+ if ( n != nHighlightedItem )
+ {
+ ChangeHighlightItem( (sal_uInt16)n, false );
+ }
+
+ bool bAllowNewPopup = true;
+ if ( pActivePopup )
+ {
+ MenuItemData* pData = pMenu->pItemList->GetDataFromPos( n );
+ bAllowNewPopup = pData && ( pData->pSubMenu != pActivePopup );
+ if ( bAllowNewPopup )
+ KillActivePopup();
+ }
+
+ if ( bPopupArea && bAllowNewPopup )
+ {
+ HighlightChanged( NULL );
+ }
+ }
+ else
+ {
+ if ( n != nHighlightedItem )
+ {
+ ChangeHighlightItem( (sal_uInt16)n, true );
+ }
+ else if ( pItemData->nBits & MIB_POPUPSELECT )
+ {
+ if ( bPopupArea && ( pActivePopup != pItemData->pSubMenu ) )
+ HighlightChanged( NULL );
+ }
+ }
+ bHighlighted = true;
+ }
+ }
+ }
+ if ( !bHighlighted )
+ ChangeHighlightItem( ITEMPOS_INVALID, true );
+ }
+ else
+ {
+ ImplScroll( rMEvt.GetPosPixel() );
+ ChangeHighlightItem( ITEMPOS_INVALID, true );
+ }
+}
+
+IMPL_LINK_NOARG(MenuFloatingWindow, PopupEnd)
+{
+ // "this" will be deleted before the end of this method!
+ Menu* pM = pMenu;
+ if ( bInExecute )
+ {
+ if ( pActivePopup )
+ {
+ //DBG_ASSERT( !pActivePopup->ImplGetWindow(), "PopupEnd, obwohl pActivePopup MIT Window!" );
+ KillActivePopup(); // should be ok to just remove it
+ //pActivePopup->bCanceled = true;
+ }
+ bInExecute = false;
+ pMenu->bInCallback = true;
+ pMenu->Deactivate();
+ pMenu->bInCallback = false;
+ }
+ else
+ {
+ if (pMenu)
+ pMenu->CloseStartedFrom();
+ }
+
+ if ( pM )
+ pM->pStartedFrom = 0;
+
+ return 0;
+}
+
+IMPL_LINK_NOARG(MenuFloatingWindow, AutoScroll)
+{
+ ImplScroll( GetPointerPosPixel() );
+ return 1;
+}
+
+IMPL_LINK( MenuFloatingWindow, HighlightChanged, Timer*, pTimer )
+{
+ if( ! pMenu )
+ return 0;
+
+ MenuItemData* pItemData = pMenu->pItemList->GetDataFromPos( nHighlightedItem );
+ if ( pItemData )
+ {
+ if ( pActivePopup && ( pActivePopup != pItemData->pSubMenu ) )
+ {
+ sal_uLong nOldFlags = GetPopupModeFlags();
+ SetPopupModeFlags( GetPopupModeFlags() | FLOATWIN_POPUPMODE_NOAPPFOCUSCLOSE );
+ KillActivePopup();
+ SetPopupModeFlags( nOldFlags );
+ }
+ if ( pItemData->bEnabled && pItemData->pSubMenu && pItemData->pSubMenu->GetItemCount() && ( pItemData->pSubMenu != pActivePopup ) )
+ {
+ pActivePopup = (PopupMenu*)pItemData->pSubMenu;
+ long nY = nScrollerHeight+ImplGetStartY();
+ MenuItemData* pData = 0;
+ for ( sal_uLong n = 0; n < nHighlightedItem; n++ )
+ {
+ pData = pMenu->pItemList->GetDataFromPos( n );
+ nY += pData->aSz.Height();
+ }
+ pData = pMenu->pItemList->GetDataFromPos( nHighlightedItem );
+ Size MySize = GetOutputSizePixel();
+ Point aItemTopLeft( 0, nY );
+ Point aItemBottomRight( aItemTopLeft );
+ aItemBottomRight.X() += MySize.Width();
+ aItemBottomRight.Y() += pData->aSz.Height();
+
+ // shift the popups a little
+ aItemTopLeft.X() += 2;
+ aItemBottomRight.X() -= 2;
+ if ( nHighlightedItem )
+ aItemTopLeft.Y() -= 2;
+ else
+ {
+ sal_Int32 nL, nT, nR, nB;
+ GetBorder( nL, nT, nR, nB );
+ aItemTopLeft.Y() -= nT;
+ }
+
+ // pTest: crash due to Reschedule() in call of Activate()
+ // Also it is prevented that submenus are displayed which
+ // were for long in Activate Rescheduled and which should not be
+ // displayed now.
+ Menu* pTest = pActivePopup;
+ sal_uLong nOldFlags = GetPopupModeFlags();
+ SetPopupModeFlags( GetPopupModeFlags() | FLOATWIN_POPUPMODE_NOAPPFOCUSCLOSE );
+ sal_uInt16 nRet = pActivePopup->ImplExecute( this, Rectangle( aItemTopLeft, aItemBottomRight ), FLOATWIN_POPUPMODE_RIGHT, pMenu, pTimer ? false : true );
+ SetPopupModeFlags( nOldFlags );
+
+ // nRet != 0, wenn es waerend Activate() abgeschossen wurde...
+ if ( !nRet && ( pActivePopup == pTest ) && pActivePopup->ImplGetWindow() )
+ pActivePopup->ImplGetFloatingWindow()->AddPopupModeWindow( this );
+ }
+ }
+
+ return 0;
+}
+
+IMPL_LINK_NOARG(MenuFloatingWindow, SubmenuClose)
+{
+ if( pMenu && pMenu->pStartedFrom )
+ {
+ MenuFloatingWindow* pWin = (MenuFloatingWindow*) pMenu->pStartedFrom->GetWindow();
+ if( pWin )
+ pWin->KillActivePopup();
+ }
+ return 0;
+}
+
+IMPL_LINK( MenuFloatingWindow, ShowHideListener, VclWindowEvent*, pEvent )
+{
+ if( ! pMenu )
+ return 0;
+
+ if( pEvent->GetId() == VCLEVENT_WINDOW_SHOW )
+ pMenu->ImplCallEventListeners( VCLEVENT_MENU_SHOW, ITEMPOS_INVALID );
+ else if( pEvent->GetId() == VCLEVENT_WINDOW_HIDE )
+ pMenu->ImplCallEventListeners( VCLEVENT_MENU_HIDE, ITEMPOS_INVALID );
+ return 0;
+}
+
+void MenuFloatingWindow::EnableScrollMenu( bool b )
+{
+ bScrollMenu = b;
+ nScrollerHeight = b ? (sal_uInt16) GetSettings().GetStyleSettings().GetScrollBarSize() /2 : 0;
+ bScrollDown = true;
+ InitMenuClipRegion();
+}
+
+void MenuFloatingWindow::Execute()
+{
+ ImplSVData* pSVData = ImplGetSVData();
+
+ pSVData->maAppData.mpActivePopupMenu = (PopupMenu*)pMenu;
+
+ bInExecute = true;
+// bCallingSelect = false;
+
+ while ( bInExecute )
+ Application::Yield();
+
+ pSVData->maAppData.mpActivePopupMenu = NULL;
+}
+
+void MenuFloatingWindow::StopExecute( sal_uLong nFocusId )
+{
+ // restore focus
+ // (could have been restored in Select)
+ if ( nSaveFocusId )
+ {
+ Window::EndSaveFocus( nFocusId, false );
+ nFocusId = nSaveFocusId;
+ if ( nFocusId )
+ {
+ nSaveFocusId = 0;
+ ImplGetSVData()->maWinData.mbNoDeactivate = false;
+ }
+ }
+ ImplEndPopupMode( 0, nFocusId );
+
+ aHighlightChangedTimer.Stop();
+ bInExecute = false;
+ if ( pActivePopup )
+ {
+ KillActivePopup();
+ }
+ // notify parent, needed for accessibility
+ if( pMenu && pMenu->pStartedFrom )
+ pMenu->pStartedFrom->ImplCallEventListeners( VCLEVENT_MENU_SUBMENUDEACTIVATE, nPosInParent );
+}
+
+void MenuFloatingWindow::KillActivePopup( PopupMenu* pThisOnly )
+{
+ if ( pActivePopup && ( !pThisOnly || ( pThisOnly == pActivePopup ) ) )
+ {
+ if( pActivePopup->pWindow != NULL )
+ if( ((FloatingWindow *) pActivePopup->pWindow)->IsInCleanUp() )
+ return; // kill it later
+ if ( pActivePopup->bInCallback )
+ pActivePopup->bCanceled = true;
+
+ // For all actions pActivePopup = 0, if e.g.
+ // PopupModeEndHdl the popups to destroy were called synchronous
+ PopupMenu* pPopup = pActivePopup;
+ pActivePopup = NULL;
+ pPopup->bInCallback = true;
+ pPopup->Deactivate();
+ pPopup->bInCallback = false;
+ if ( pPopup->ImplGetWindow() )
+ {
+ pPopup->ImplGetFloatingWindow()->StopExecute();
+ pPopup->ImplGetFloatingWindow()->doShutdown();
+ pPopup->pWindow->doLazyDelete();
+ pPopup->pWindow = NULL;
+
+ Update();
+ }
+ }
+}
+
+void MenuFloatingWindow::EndExecute()
+{
+ Menu* pStart = pMenu ? pMenu->ImplGetStartMenu() : NULL;
+ sal_uLong nFocusId = 0;
+ if (pStart)
+ nFocusId = pStart->DeactivateMenuBar(nFocusId);
+
+ // if started elsewhere, cleanup there as well
+ MenuFloatingWindow* pCleanUpFrom = this;
+ MenuFloatingWindow* pWin = this;
+ while ( pWin && !pWin->bInExecute &&
+ pWin->pMenu->pStartedFrom && !pWin->pMenu->pStartedFrom->bIsMenuBar )
+ {
+ pWin = ((PopupMenu*)pWin->pMenu->pStartedFrom)->ImplGetFloatingWindow();
+ }
+ if ( pWin )
+ pCleanUpFrom = pWin;
+
+ // this window will be destroyed => store date locally...
+ Menu* pM = pMenu;
+ sal_uInt16 nItem = nHighlightedItem;
+
+ pCleanUpFrom->StopExecute( nFocusId );
+
+ if ( nItem != ITEMPOS_INVALID && pM )
+ {
+ MenuItemData* pItemData = pM->GetItemList()->GetDataFromPos( nItem );
+ if ( pItemData && !pItemData->bIsTemporary )
+ {
+ pM->nSelectedId = pItemData->nId;
+ if ( pStart )
+ pStart->nSelectedId = pItemData->nId;
+
+ pM->ImplSelect();
+ }
+ }
+}
+
+void MenuFloatingWindow::EndExecute( sal_uInt16 nId )
+{
+ size_t nPos;
+ if ( pMenu && pMenu->GetItemList()->GetData( nId, nPos ) )
+ nHighlightedItem = nPos;
+ else
+ nHighlightedItem = ITEMPOS_INVALID;
+
+ EndExecute();
+}
+
+void MenuFloatingWindow::MouseButtonDown( const MouseEvent& rMEvt )
+{
+ // TH creates a ToTop on this window, but the active popup
+ // should stay on top...
+ // due to focus change this would close all menus -> don't do it (#94123)
+ //if ( pActivePopup && pActivePopup->ImplGetWindow() && !pActivePopup->ImplGetFloatingWindow()->pActivePopup )
+ // pActivePopup->ImplGetFloatingWindow()->ToTop( TOTOP_NOGRABFOCUS );
+
+ ImplHighlightItem( rMEvt, true );
+
+ nMBDownPos = nHighlightedItem;
+}
+
+void MenuFloatingWindow::MouseButtonUp( const MouseEvent& rMEvt )
+{
+ MenuItemData* pData = pMenu ? pMenu->GetItemList()->GetDataFromPos( nHighlightedItem ) : NULL;
+ // nMBDownPos store in local variable and reset immediately,
+ // as it will be too late after EndExecute
+ sal_uInt16 _nMBDownPos = nMBDownPos;
+ nMBDownPos = ITEMPOS_INVALID;
+ if ( pData && pData->bEnabled && ( pData->eType != MENUITEM_SEPARATOR ) )
+ {
+ if ( !pData->pSubMenu )
+ {
+ EndExecute();
+ }
+ else if ( ( pData->nBits & MIB_POPUPSELECT ) && ( nHighlightedItem == _nMBDownPos ) && ( rMEvt.GetClicks() == 2 ) )
+ {
+ // not when clicked over the arrow...
+ Size aSz = GetOutputSizePixel();
+ long nFontHeight = GetTextHeight();
+ if ( rMEvt.GetPosPixel().X() < ( aSz.Width() - nFontHeight - nFontHeight/4 ) )
+ EndExecute();
+ }
+ }
+
+}
+
+void MenuFloatingWindow::MouseMove( const MouseEvent& rMEvt )
+{
+ if ( !IsVisible() || rMEvt.IsSynthetic() || rMEvt.IsEnterWindow() )
+ return;
+
+ if ( rMEvt.IsLeaveWindow() )
+ {
+ // #102461# do not remove highlight if a popup menu is open at this position
+ MenuItemData* pData = pMenu ? pMenu->pItemList->GetDataFromPos( nHighlightedItem ) : NULL;
+ // close popup with some delayed if we leave somewhere else
+ if( pActivePopup && pData && pData->pSubMenu != pActivePopup )
+ pActivePopup->ImplGetFloatingWindow()->aSubmenuCloseTimer.Start();
+
+ if( !pActivePopup || (pData && pData->pSubMenu != pActivePopup ) )
+ ChangeHighlightItem( ITEMPOS_INVALID, false );
+
+ if ( IsScrollMenu() )
+ ImplScroll( rMEvt.GetPosPixel() );
+ }
+ else
+ {
+ aSubmenuCloseTimer.Stop();
+ if( bIgnoreFirstMove )
+ bIgnoreFirstMove = false;
+ else
+ ImplHighlightItem( rMEvt, false );
+ }
+}
+
+void MenuFloatingWindow::ImplScroll( bool bUp )
+{
+ KillActivePopup();
+ Update();
+
+ if( ! pMenu )
+ return;
+
+ HighlightItem( nHighlightedItem, false );
+
+ pMenu->ImplKillLayoutData();
+
+ if ( bScrollUp && bUp )
+ {
+ nFirstEntry = pMenu->ImplGetPrevVisible( nFirstEntry );
+ DBG_ASSERT( nFirstEntry != ITEMPOS_INVALID, "Scroll?!" );
+
+ long nScrollEntryHeight = pMenu->GetItemList()->GetDataFromPos( nFirstEntry )->aSz.Height();
+
+ if ( !bScrollDown )
+ {
+ bScrollDown = true;
+ ImplDrawScroller( false );
+ }
+
+ if ( pMenu->ImplGetPrevVisible( nFirstEntry ) == ITEMPOS_INVALID )
+ {
+ bScrollUp = false;
+ ImplDrawScroller( true );
+ }
+
+ Scroll( 0, nScrollEntryHeight, ImplCalcClipRegion( false ).GetBoundRect(), SCROLL_CLIP );
+ }
+ else if ( bScrollDown && !bUp )
+ {
+ long nScrollEntryHeight = pMenu->GetItemList()->GetDataFromPos( nFirstEntry )->aSz.Height();
+
+ nFirstEntry = pMenu->ImplGetNextVisible( nFirstEntry );
+ DBG_ASSERT( nFirstEntry != ITEMPOS_INVALID, "Scroll?!" );
+
+ if ( !bScrollUp )
+ {
+ bScrollUp = true;
+ ImplDrawScroller( true );
+ }
+
+ long nHeight = GetOutputSizePixel().Height();
+ sal_uInt16 nLastVisible;
+ ((PopupMenu*)pMenu)->ImplCalcVisEntries( nHeight, nFirstEntry, &nLastVisible );
+ if ( pMenu->ImplGetNextVisible( nLastVisible ) == ITEMPOS_INVALID )
+ {
+ bScrollDown = false;
+ ImplDrawScroller( false );
+ }
+
+ Scroll( 0, -nScrollEntryHeight, ImplCalcClipRegion( false ).GetBoundRect(), SCROLL_CLIP );
+ }
+
+ HighlightItem( nHighlightedItem, true );
+}
+
+void MenuFloatingWindow::ImplScroll( const Point& rMousePos )
+{
+ Size aOutSz = GetOutputSizePixel();
+
+ long nY = nScrollerHeight;
+ long nMouseY = rMousePos.Y();
+ long nDelta = 0;
+
+ if ( bScrollUp && ( nMouseY < nY ) )
+ {
+ ImplScroll( true );
+ nDelta = nY - nMouseY;
+ }
+ else if ( bScrollDown && ( nMouseY > ( aOutSz.Height() - nY ) ) )
+ {
+ ImplScroll( false );
+ nDelta = nMouseY - ( aOutSz.Height() - nY );
+ }
+
+ if ( nDelta )
+ {
+ aScrollTimer.Stop(); // if scrolled through MouseMove.
+ long nTimeout;
+ if ( nDelta < 3 )
+ nTimeout = 200;
+ else if ( nDelta < 5 )
+ nTimeout = 100;
+ else if ( nDelta < 8 )
+ nTimeout = 70;
+ else if ( nDelta < 12 )
+ nTimeout = 40;
+ else
+ nTimeout = 20;
+ aScrollTimer.SetTimeout( nTimeout );
+ aScrollTimer.Start();
+ }
+}
+void MenuFloatingWindow::ChangeHighlightItem( sal_uInt16 n, bool bStartPopupTimer )
+{
+ // #57934# ggf. immediately close the active, as TH's backgroundstorage works.
+ // #65750# we prefer to refrain from the background storage of small lines.
+ // otherwise the menus are difficult to operate.
+ // MenuItemData* pNextData = pMenu->pItemList->GetDataFromPos( n );
+ // if ( pActivePopup && pNextData && ( pActivePopup != pNextData->pSubMenu ) )
+ // KillActivePopup();
+
+ aSubmenuCloseTimer.Stop();
+ if( ! pMenu )
+ return;
+
+ if ( nHighlightedItem != ITEMPOS_INVALID )
+ {
+ HighlightItem( nHighlightedItem, false );
+ pMenu->ImplCallEventListeners( VCLEVENT_MENU_DEHIGHLIGHT, nHighlightedItem );
+ }
+
+ nHighlightedItem = (sal_uInt16)n;
+ DBG_ASSERT( pMenu->ImplIsVisible( nHighlightedItem ) || nHighlightedItem == ITEMPOS_INVALID, "ChangeHighlightItem: Not visible!" );
+ if( nHighlightedItem != ITEMPOS_INVALID )
+ {
+ if( pMenu->pStartedFrom && !pMenu->pStartedFrom->bIsMenuBar )
+ {
+ // #102461# make sure parent entry is highlighted as well
+ MenuItemData* pData;
+ size_t i, nCount = pMenu->pStartedFrom->pItemList->size();
+ for(i = 0; i < nCount; i++)
+ {
+ pData = pMenu->pStartedFrom->pItemList->GetDataFromPos( i );
+ if( pData && ( pData->pSubMenu == pMenu ) )
+ break;
+ }
+ if( i < nCount )
+ {
+ MenuFloatingWindow* pPWin = (MenuFloatingWindow*)pMenu->pStartedFrom->ImplGetWindow();
+ if( pPWin && pPWin->nHighlightedItem != i )
+ {
+ pPWin->HighlightItem( i, true );
+ pPWin->nHighlightedItem = i;
+ }
+ }
+ }
+ HighlightItem( nHighlightedItem, true );
+ pMenu->SetHighlightItem(nHighlightedItem);
+ pMenu->ImplCallHighlight( nHighlightedItem );
+ }
+ else
+ pMenu->nSelectedId = 0;
+
+ if ( bStartPopupTimer )
+ {
+ // #102438# Menu items are not selectable
+ // If a menu item is selected by an AT-tool via the XAccessibleAction, XAccessibleValue
+ // or XAccessibleSelection interface, and the parent popup menus are not executed yet,
+ // the parent popup menus must be executed SYNCHRONOUSLY, before the menu item is selected.
+ if ( GetSettings().GetMouseSettings().GetMenuDelay() )
+ aHighlightChangedTimer.Start();
+ else
+ HighlightChanged( &aHighlightChangedTimer );
+ }
+}
+
+void MenuFloatingWindow::HighlightItem( sal_uInt16 nPos, bool bHighlight )
+{
+ if( ! pMenu )
+ return;
+
+ Size aSz = GetOutputSizePixel();
+ long nStartY = ImplGetStartY();
+ long nY = nScrollerHeight + nStartY + ImplGetSVData()->maNWFData.mnMenuFormatBorderY;
+ long nX = 0;
+
+ if ( pMenu->pLogo )
+ nX = pMenu->pLogo->aBitmap.GetSizePixel().Width();
+
+ int nOuterSpaceX = ImplGetSVData()->maNWFData.mnMenuFormatBorderX;
+
+ size_t nCount = pMenu->pItemList->size();
+ for ( size_t n = 0; n < nCount; n++ )
+ {
+ MenuItemData* pData = pMenu->pItemList->GetDataFromPos( n );
+ if ( n == nPos )
+ {
+ DBG_ASSERT( pMenu->ImplIsVisible( n ), "Highlight: Item not visible!" );
+ if ( pData->eType != MENUITEM_SEPARATOR )
+ {
+ bool bRestoreLineColor = false;
+ Color oldLineColor;
+ bool bDrawItemRect = true;
+
+ Rectangle aItemRect( Point( nX+nOuterSpaceX, nY ), Size( aSz.Width()-2*nOuterSpaceX, pData->aSz.Height() ) );
+ if ( pData->nBits & MIB_POPUPSELECT )
+ {
+ long nFontHeight = GetTextHeight();
+ aItemRect.Right() -= nFontHeight + nFontHeight/4;
+ }
+
+ if( IsNativeControlSupported( CTRL_MENU_POPUP, PART_ENTIRE_CONTROL ) )
+ {
+ Size aPxSize( GetOutputSizePixel() );
+ Push( PUSH_CLIPREGION );
+ IntersectClipRegion( Rectangle( Point( nX, nY ), Size( aSz.Width(), pData->aSz.Height() ) ) );
+ Rectangle aCtrlRect( Point( nX, 0 ), Size( aPxSize.Width()-nX, aPxSize.Height() ) );
+ MenupopupValue aVal( pMenu->nTextPos-GUTTERBORDER, aItemRect );
+ DrawNativeControl( CTRL_MENU_POPUP, PART_ENTIRE_CONTROL,
+ aCtrlRect,
+ CTRL_STATE_ENABLED,
+ aVal,
+ OUString() );
+ if( bHighlight &&
+ IsNativeControlSupported( CTRL_MENU_POPUP, PART_MENU_ITEM ) )
+ {
+ bDrawItemRect = false;
+ if( !DrawNativeControl( CTRL_MENU_POPUP, PART_MENU_ITEM,
+ aItemRect,
+ CTRL_STATE_SELECTED | ( pData->bEnabled? CTRL_STATE_ENABLED: 0 ),
+ aVal,
+ OUString() ) )
+ {
+ bDrawItemRect = bHighlight;
+ }
+ }
+ else
+ bDrawItemRect = bHighlight;
+ Pop();
+ }
+ if( bDrawItemRect )
+ {
+ if ( bHighlight )
+ {
+ if( pData->bEnabled )
+ SetFillColor( GetSettings().GetStyleSettings().GetMenuHighlightColor() );
+ else
+ {
+ SetFillColor();
+ oldLineColor = GetLineColor();
+ SetLineColor( GetSettings().GetStyleSettings().GetMenuHighlightColor() );
+ bRestoreLineColor = true;
+ }
+ }
+ else
+ SetFillColor( GetSettings().GetStyleSettings().GetMenuColor() );
+
+ DrawRect( aItemRect );
+ }
+ pMenu->ImplPaint( this, nScrollerHeight, nStartY, pData, bHighlight );
+ if( bRestoreLineColor )
+ SetLineColor( oldLineColor );
+ }
+ return;
+ }
+
+ nY += pData->aSz.Height();
+ }
+}
+
+Rectangle MenuFloatingWindow::ImplGetItemRect( sal_uInt16 nPos )
+{
+ if( ! pMenu )
+ return Rectangle();
+
+ Rectangle aRect;
+ Size aSz = GetOutputSizePixel();
+ long nStartY = ImplGetStartY();
+ long nY = nScrollerHeight+nStartY;
+ long nX = 0;
+
+ if ( pMenu->pLogo )
+ nX = pMenu->pLogo->aBitmap.GetSizePixel().Width();
+
+ size_t nCount = pMenu->pItemList->size();
+ for ( size_t n = 0; n < nCount; n++ )
+ {
+ MenuItemData* pData = pMenu->pItemList->GetDataFromPos( n );
+ if ( n == nPos )
+ {
+ DBG_ASSERT( pMenu->ImplIsVisible( n ), "ImplGetItemRect: Item not visible!" );
+ if ( pData->eType != MENUITEM_SEPARATOR )
+ {
+ aRect = Rectangle( Point( nX, nY ), Size( aSz.Width(), pData->aSz.Height() ) );
+ if ( pData->nBits & MIB_POPUPSELECT )
+ {
+ long nFontHeight = GetTextHeight();
+ aRect.Right() -= nFontHeight + nFontHeight/4;
+ }
+ }
+ break;
+ }
+ nY += pData->aSz.Height();
+ }
+ return aRect;
+}
+
+void MenuFloatingWindow::ImplCursorUpDown( bool bUp, bool bHomeEnd )
+{
+ if( ! pMenu )
+ return;
+
+ const StyleSettings& rSettings = GetSettings().GetStyleSettings();
+
+ sal_uInt16 n = nHighlightedItem;
+ if ( n == ITEMPOS_INVALID )
+ {
+ if ( bUp )
+ n = 0;
+ else
+ n = pMenu->GetItemCount()-1;
+ }
+
+ sal_uInt16 nLoop = n;
+
+ if( bHomeEnd )
+ {
+ // absolute positioning
+ if( bUp )
+ {
+ n = pMenu->GetItemCount();
+ nLoop = n-1;
+ }
+ else
+ {
+ n = (sal_uInt16)-1;
+ nLoop = n+1;
+ }
+ }
+
+ do
+ {
+ if ( bUp )
+ {
+ if ( n )
+ n--;
+ else
+ if ( !IsScrollMenu() || ( nHighlightedItem == ITEMPOS_INVALID ) )
+ n = pMenu->GetItemCount()-1;
+ else
+ break;
+ }
+ else
+ {
+ n++;
+ if ( n >= pMenu->GetItemCount() )
+ {
+ if ( !IsScrollMenu() || ( nHighlightedItem == ITEMPOS_INVALID ) )
+ n = 0;
+ else
+ break;
+ }
+ }
+
+ MenuItemData* pData = (MenuItemData*)pMenu->GetItemList()->GetDataFromPos( n );
+ if ( ( pData->bEnabled || !rSettings.GetSkipDisabledInMenus() )
+ && ( pData->eType != MENUITEM_SEPARATOR ) && pMenu->ImplIsVisible( n ) && pMenu->ImplIsSelectable( n ) )
+ {
+ // Is selection in visible area?
+ if ( IsScrollMenu() )
+ {
+ ChangeHighlightItem( ITEMPOS_INVALID, false );
+
+ while ( n < nFirstEntry )
+ ImplScroll( true );
+
+ Size aOutSz = GetOutputSizePixel();
+ sal_uInt16 nLastVisible;
+ ((PopupMenu*)pMenu)->ImplCalcVisEntries( aOutSz.Height(), nFirstEntry, &nLastVisible );
+ while ( n > nLastVisible )
+ {
+ ImplScroll( false );
+ ((PopupMenu*)pMenu)->ImplCalcVisEntries( aOutSz.Height(), nFirstEntry, &nLastVisible );
+ }
+ }
+ ChangeHighlightItem( n, false );
+ break;
+ }
+ } while ( n != nLoop );
+}
+
+void MenuFloatingWindow::KeyInput( const KeyEvent& rKEvent )
+{
+ ImplDelData aDelData;
+ ImplAddDel( &aDelData );
+
+ sal_uInt16 nCode = rKEvent.GetKeyCode().GetCode();
+ bKeyInput = true;
+ switch ( nCode )
+ {
+ case KEY_UP:
+ case KEY_DOWN:
+ {
+ ImplCursorUpDown( nCode == KEY_UP );
+ }
+ break;
+ case KEY_END:
+ case KEY_HOME:
+ {
+ ImplCursorUpDown( nCode == KEY_END, true );
+ }
+ break;
+ case KEY_F6:
+ case KEY_ESCAPE:
+ {
+ // Ctrl-F6 acts like ESC here, the menu bar however will then put the focus in the document
+ if( nCode == KEY_F6 && !rKEvent.GetKeyCode().IsMod1() )
+ break;
+ if( pMenu )
+ {
+ if ( !pMenu->pStartedFrom )
+ {
+ StopExecute();
+ KillActivePopup();
+ }
+ else if ( pMenu->pStartedFrom->bIsMenuBar )
+ {
+ pMenu->pStartedFrom->MenuBarKeyInput(rKEvent);
+ }
+ else
+ {
+ StopExecute();
+ PopupMenu* pPopupMenu = (PopupMenu*)pMenu->pStartedFrom;
+ MenuFloatingWindow* pFloat = pPopupMenu->ImplGetFloatingWindow();
+ pFloat->GrabFocus();
+ pFloat->KillActivePopup();
+ pPopupMenu->ImplCallHighlight(pFloat->nHighlightedItem);
+ }
+ }
+ }
+ break;
+ case KEY_LEFT:
+ {
+ if ( pMenu && pMenu->pStartedFrom )
+ {
+ StopExecute();
+ if ( pMenu->pStartedFrom->bIsMenuBar )
+ {
+ pMenu->pStartedFrom->MenuBarKeyInput(rKEvent);
+ }
+ else
+ {
+ MenuFloatingWindow* pFloat = ((PopupMenu*)pMenu->pStartedFrom)->ImplGetFloatingWindow();
+ pFloat->GrabFocus();
+ pFloat->KillActivePopup();
+ sal_uInt16 highlightItem = pFloat->GetHighlightedItem();
+ pFloat->ChangeHighlightItem(highlightItem, false);
+ }
+ }
+ }
+ break;
+ case KEY_RIGHT:
+ {
+ if( pMenu )
+ {
+ bool bDone = false;
+ if ( nHighlightedItem != ITEMPOS_INVALID )
+ {
+ MenuItemData* pData = pMenu->GetItemList()->GetDataFromPos( nHighlightedItem );
+ if ( pData && pData->pSubMenu )
+ {
+ HighlightChanged( 0 );
+ bDone = true;
+ }
+ }
+ if ( !bDone )
+ {
+ Menu* pStart = pMenu->ImplGetStartMenu();
+ if ( pStart && pStart->bIsMenuBar )
+ {
+ // Forward...
+ pStart->ImplGetWindow()->KeyInput( rKEvent );
+ }
+ }
+ }
+ }
+ break;
+ case KEY_RETURN:
+ {
+ if( pMenu )
+ {
+ MenuItemData* pData = pMenu->GetItemList()->GetDataFromPos( nHighlightedItem );
+ if ( pData && pData->bEnabled )
+ {
+ if ( pData->pSubMenu )
+ HighlightChanged( 0 );
+ else
+ EndExecute();
+ }
+ else
+ StopExecute();
+ }
+ }
+ break;
+ case KEY_MENU:
+ {
+ if( pMenu )
+ {
+ Menu* pStart = pMenu->ImplGetStartMenu();
+ if ( pStart && pStart->bIsMenuBar )
+ {
+ // Forward...
+ pStart->ImplGetWindow()->KeyInput( rKEvent );
+ }
+ }
+ }
+ break;
+ default:
+ {
+ sal_Unicode nCharCode = rKEvent.GetCharCode();
+ sal_uInt16 nPos = 0;
+ sal_uInt16 nDuplicates = 0;
+ MenuItemData* pData = (nCharCode && pMenu) ? pMenu->GetItemList()->SearchItem( nCharCode, rKEvent.GetKeyCode(), nPos, nDuplicates, nHighlightedItem ) : NULL;
+ if ( pData )
+ {
+ if ( pData->pSubMenu || nDuplicates > 1 )
+ {
+ ChangeHighlightItem( nPos, false );
+ HighlightChanged( 0 );
+ }
+ else
+ {
+ nHighlightedItem = nPos;
+ EndExecute();
+ }
+ }
+ else
+ FloatingWindow::KeyInput( rKEvent );
+ }
+ }
+ // #105474# check if menu window was not destroyed
+ if ( !aDelData.IsDead() )
+ {
+ ImplRemoveDel( &aDelData );
+ bKeyInput = false;
+ }
+}
+
+void MenuFloatingWindow::Paint( const Rectangle& )
+{
+ if( ! pMenu )
+ return;
+
+ if( IsNativeControlSupported( CTRL_MENU_POPUP, PART_ENTIRE_CONTROL ) )
+ {
+ SetClipRegion();
+ long nX = pMenu->pLogo ? pMenu->pLogo->aBitmap.GetSizePixel().Width() : 0;
+ Size aPxSize( GetOutputSizePixel() );
+ aPxSize.Width() -= nX;
+ ImplControlValue aVal( pMenu->nTextPos-GUTTERBORDER );
+ DrawNativeControl( CTRL_MENU_POPUP, PART_ENTIRE_CONTROL,
+ Rectangle( Point( nX, 0 ), aPxSize ),
+ CTRL_STATE_ENABLED,
+ aVal,
+ OUString() );
+ InitMenuClipRegion();
+ }
+ if ( IsScrollMenu() )
+ {
+ ImplDrawScroller( true );
+ ImplDrawScroller( false );
+ }
+ SetFillColor( GetSettings().GetStyleSettings().GetMenuColor() );
+ pMenu->ImplPaint( this, nScrollerHeight, ImplGetStartY() );
+ if ( nHighlightedItem != ITEMPOS_INVALID )
+ HighlightItem( nHighlightedItem, true );
+}
+
+void MenuFloatingWindow::ImplDrawScroller( bool bUp )
+{
+ if( ! pMenu )
+ return;
+
+ SetClipRegion();
+
+ Size aOutSz = GetOutputSizePixel();
+ long nY = bUp ? 0 : ( aOutSz.Height() - nScrollerHeight );
+ long nX = pMenu->pLogo ? pMenu->pLogo->aBitmap.GetSizePixel().Width() : 0;
+ Rectangle aRect( Point( nX, nY ), Size( aOutSz.Width()-nX, nScrollerHeight ) );
+
+ DecorationView aDecoView( this );
+ SymbolType eSymbol = bUp ? SYMBOL_SPIN_UP : SYMBOL_SPIN_DOWN;
+
+ sal_uInt16 nStyle = 0;
+ if ( ( bUp && !bScrollUp ) || ( !bUp && !bScrollDown ) )
+ nStyle |= SYMBOL_DRAW_DISABLE;
+
+ aDecoView.DrawSymbol( aRect, eSymbol, GetSettings().GetStyleSettings().GetButtonTextColor(), nStyle );
+
+ InitMenuClipRegion();
+}
+
+void MenuFloatingWindow::RequestHelp( const HelpEvent& rHEvt )
+{
+ sal_uInt16 nId = nHighlightedItem;
+ Menu* pM = pMenu;
+ Window* pW = this;
+
+ // #102618# Get item rect before destroying the window in EndExecute() call
+ Rectangle aHighlightRect( ImplGetItemRect( nHighlightedItem ) );
+
+ if ( rHEvt.GetMode() & (HELPMODE_CONTEXT | HELPMODE_EXTENDED) )
+ {
+ nHighlightedItem = ITEMPOS_INVALID;
+ EndExecute();
+ pW = NULL;
+ }
+
+ if( !ImplHandleHelpEvent( pW, pM, nId, rHEvt, aHighlightRect ) )
+ Window::RequestHelp( rHEvt );
+}
+
+void MenuFloatingWindow::StateChanged( StateChangedType nType )
+{
+ FloatingWindow::StateChanged( nType );
+
+ if ( ( nType == STATE_CHANGE_CONTROLFOREGROUND ) || ( nType == STATE_CHANGE_CONTROLBACKGROUND ) )
+ {
+ ImplInitMenuWindow( this, false, false );
+ Invalidate();
+ }
+}
+
+void MenuFloatingWindow::DataChanged( const DataChangedEvent& rDCEvt )
+{
+ FloatingWindow::DataChanged( rDCEvt );
+
+ if ( (rDCEvt.GetType() == DATACHANGED_FONTS) ||
+ (rDCEvt.GetType() == DATACHANGED_FONTSUBSTITUTION) ||
+ ((rDCEvt.GetType() == DATACHANGED_SETTINGS) &&
+ (rDCEvt.GetFlags() & SETTINGS_STYLE)) )
+ {
+ ImplInitMenuWindow( this, false, false );
+ Invalidate();
+ }
+}
+
+void MenuFloatingWindow::Command( const CommandEvent& rCEvt )
+{
+ if ( rCEvt.GetCommand() == COMMAND_WHEEL )
+ {
+ const CommandWheelData* pData = rCEvt.GetWheelData();
+ if( !pData->GetModifier() && ( pData->GetMode() == COMMAND_WHEEL_SCROLL ) )
+ {
+// ImplCursorUpDown( pData->GetDelta() > 0L );
+ ImplScroll( pData->GetDelta() > 0L );
+ MouseMove( MouseEvent( GetPointerPosPixel(), 0 ) );
+ }
+ }
+}
+
+::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible > MenuFloatingWindow::CreateAccessible()
+{
+ ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible > xAcc;
+
+ if ( pMenu && !pMenu->pStartedFrom )
+ xAcc = pMenu->GetAccessible();
+
+ return xAcc;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/source/window/menufloatingwindow.hxx b/vcl/source/window/menufloatingwindow.hxx
new file mode 100644
index 000000000000..c2f84c7eb2ab
--- /dev/null
+++ b/vcl/source/window/menufloatingwindow.hxx
@@ -0,0 +1,121 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_VCL_SOURCE_WINDOW_MENUFLOATINGWINDOW_HXX
+#define INCLUDED_VCL_SOURCE_WINDOW_MENUFLOATINGWINDOW_HXX
+
+#include "menuwindow.hxx"
+
+#include <vcl/floatwin.hxx>
+#include <vcl/menu.hxx>
+
+#define EXTRASPACEY 2
+#define GUTTERBORDER 8
+
+/** Class that implements the actual window of the floating menu.
+*/
+class MenuFloatingWindow : public MenuWindow, public FloatingWindow
+{
+ friend void Menu::ImplFillLayoutData() const;
+ friend Menu::~Menu();
+
+private:
+ Menu* pMenu;
+ PopupMenu* pActivePopup;
+ Timer aHighlightChangedTimer;
+ Timer aSubmenuCloseTimer;
+ Timer aScrollTimer;
+ sal_uLong nSaveFocusId;
+ sal_uInt16 nHighlightedItem; // highlighted/selected Item
+ sal_uInt16 nMBDownPos;
+ sal_uInt16 nScrollerHeight;
+ sal_uInt16 nFirstEntry;
+ sal_uInt16 nBorder;
+ sal_uInt16 nPosInParent;
+ bool bInExecute;
+
+ bool bScrollMenu;
+ bool bScrollUp;
+ bool bScrollDown;
+ bool bIgnoreFirstMove;
+ bool bKeyInput;
+
+ DECL_LINK(PopupEnd, void *);
+ DECL_LINK( HighlightChanged, Timer* );
+ DECL_LINK(SubmenuClose, void *);
+ DECL_LINK(AutoScroll, void *);
+ DECL_LINK( ShowHideListener, VclWindowEvent* );
+
+ virtual void StateChanged( StateChangedType nType ) SAL_OVERRIDE;
+ virtual void DataChanged( const DataChangedEvent& rDCEvt ) SAL_OVERRIDE;
+
+ void InitMenuClipRegion();
+
+protected:
+ Region ImplCalcClipRegion( bool bIncludeLogo = true ) const;
+ void ImplDrawScroller( bool bUp );
+ using Window::ImplScroll;
+ void ImplScroll( const Point& rMousePos );
+ void ImplScroll( bool bUp );
+ void ImplCursorUpDown( bool bUp, bool bHomeEnd = false );
+ void ImplHighlightItem( const MouseEvent& rMEvt, bool bMBDown );
+ long ImplGetStartY() const;
+ Rectangle ImplGetItemRect( sal_uInt16 nPos );
+
+public:
+ MenuFloatingWindow( Menu* pMenu, Window* pParent, WinBits nStyle );
+ virtual ~MenuFloatingWindow();
+
+ void doShutdown();
+
+ virtual void MouseMove( const MouseEvent& rMEvt ) SAL_OVERRIDE;
+ virtual void MouseButtonDown( const MouseEvent& rMEvt ) SAL_OVERRIDE;
+ virtual void MouseButtonUp( const MouseEvent& rMEvt ) SAL_OVERRIDE;
+ virtual void KeyInput( const KeyEvent& rKEvent ) SAL_OVERRIDE;
+ virtual void Command( const CommandEvent& rCEvt ) SAL_OVERRIDE;
+ virtual void Paint( const Rectangle& rRect ) SAL_OVERRIDE;
+ virtual void RequestHelp( const HelpEvent& rHEvt ) SAL_OVERRIDE;
+ virtual void Resize() SAL_OVERRIDE;
+
+ void SetFocusId( sal_uLong nId ) { nSaveFocusId = nId; }
+ sal_uLong GetFocusId() const { return nSaveFocusId; }
+
+ void EnableScrollMenu( bool b );
+ bool IsScrollMenu() const { return bScrollMenu; }
+ sal_uInt16 GetScrollerHeight() const { return nScrollerHeight; }
+
+ void Execute();
+ void StopExecute( sal_uLong nFocusId = 0 );
+ void EndExecute();
+ void EndExecute( sal_uInt16 nSelectId );
+
+ PopupMenu* GetActivePopup() const { return pActivePopup; }
+ void KillActivePopup( PopupMenu* pThisOnly = NULL );
+
+ void HighlightItem( sal_uInt16 nPos, bool bHighlight );
+ void ChangeHighlightItem( sal_uInt16 n, bool bStartPopupTimer );
+ sal_uInt16 GetHighlightedItem() const { return nHighlightedItem; }
+
+ void SetPosInParent( sal_uInt16 nPos ) { nPosInParent = nPos; }
+
+ virtual ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible > CreateAccessible() SAL_OVERRIDE;
+};
+
+#endif // INCLUDED_VCL_SOURCE_WINDOW_MENUFLOATINGWINDOW_HXX
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/source/window/menuitemlist.cxx b/vcl/source/window/menuitemlist.cxx
new file mode 100644
index 000000000000..4fe0a0a23922
--- /dev/null
+++ b/vcl/source/window/menuitemlist.cxx
@@ -0,0 +1,280 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "menuitemlist.hxx"
+
+#include <salframe.hxx>
+#include <salinst.hxx>
+#include <salmenu.hxx>
+#include <svdata.hxx>
+#include <vcl/i18nhelp.hxx>
+#include <vcl/settings.hxx>
+#include <vcl/window.hxx>
+
+using namespace css;
+using namespace vcl;
+
+MenuItemData::~MenuItemData()
+{
+ if( pAutoSubMenu )
+ {
+ ((PopupMenu*)pAutoSubMenu)->pRefAutoSubMenu = NULL;
+ delete pAutoSubMenu;
+ pAutoSubMenu = NULL;
+ }
+ if( pSalMenuItem )
+ ImplGetSVData()->mpDefInst->DestroyMenuItem( pSalMenuItem );
+}
+
+MenuItemList::~MenuItemList()
+{
+ for( size_t i = 0, n = maItemList.size(); i < n; ++i )
+ delete maItemList[ i ];
+}
+
+MenuItemData* MenuItemList::Insert(
+ sal_uInt16 nId,
+ MenuItemType eType,
+ MenuItemBits nBits,
+ const OUString& rStr,
+ const Image& rImage,
+ Menu* pMenu,
+ size_t nPos,
+ const OString &rIdent
+)
+{
+ MenuItemData* pData = new MenuItemData( rStr, rImage );
+ pData->nId = nId;
+ pData->sIdent = rIdent;
+ pData->eType = eType;
+ pData->nBits = nBits;
+ pData->pSubMenu = NULL;
+ pData->pAutoSubMenu = NULL;
+ pData->nUserValue = 0;
+ pData->bChecked = false;
+ pData->bEnabled = true;
+ pData->bVisible = true;
+ pData->bIsTemporary = false;
+ pData->bMirrorMode = false;
+ pData->nItemImageAngle = 0;
+
+ SalItemParams aSalMIData;
+ aSalMIData.nId = nId;
+ aSalMIData.eType = eType;
+ aSalMIData.nBits = nBits;
+ aSalMIData.pMenu = pMenu;
+ aSalMIData.aText = rStr;
+ aSalMIData.aImage = rImage;
+
+ // Native-support: returns NULL if not supported
+ pData->pSalMenuItem = ImplGetSVData()->mpDefInst->CreateMenuItem( &aSalMIData );
+
+ if( nPos < maItemList.size() ) {
+ maItemList.insert( maItemList.begin() + nPos, pData );
+ } else {
+ maItemList.push_back( pData );
+ }
+ return pData;
+}
+
+void MenuItemList::InsertSeparator(const OString &rIdent, size_t nPos)
+{
+ MenuItemData* pData = new MenuItemData;
+ pData->nId = 0;
+ pData->sIdent = rIdent;
+ pData->eType = MENUITEM_SEPARATOR;
+ pData->nBits = 0;
+ pData->pSubMenu = NULL;
+ pData->pAutoSubMenu = NULL;
+ pData->nUserValue = 0;
+ pData->bChecked = false;
+ pData->bEnabled = true;
+ pData->bVisible = true;
+ pData->bIsTemporary = false;
+ pData->bMirrorMode = false;
+ pData->nItemImageAngle = 0;
+
+ SalItemParams aSalMIData;
+ aSalMIData.nId = 0;
+ aSalMIData.eType = MENUITEM_SEPARATOR;
+ aSalMIData.nBits = 0;
+ aSalMIData.pMenu = NULL;
+ aSalMIData.aText = OUString();
+ aSalMIData.aImage = Image();
+
+ // Native-support: returns NULL if not supported
+ pData->pSalMenuItem = ImplGetSVData()->mpDefInst->CreateMenuItem( &aSalMIData );
+
+ if( nPos < maItemList.size() ) {
+ maItemList.insert( maItemList.begin() + nPos, pData );
+ } else {
+ maItemList.push_back( pData );
+ }
+}
+
+void MenuItemList::Remove( size_t nPos )
+{
+ if( nPos < maItemList.size() )
+ {
+ delete maItemList[ nPos ];
+ maItemList.erase( maItemList.begin() + nPos );
+ }
+}
+
+MenuItemData* MenuItemList::GetData( sal_uInt16 nSVId, size_t& rPos ) const
+{
+ for( size_t i = 0, n = maItemList.size(); i < n; ++i )
+ {
+ if ( maItemList[ i ]->nId == nSVId )
+ {
+ rPos = i;
+ return maItemList[ i ];
+ }
+ }
+ return NULL;
+}
+
+MenuItemData* MenuItemList::SearchItem(
+ sal_Unicode cSelectChar,
+ KeyCode aKeyCode,
+ sal_uInt16& rPos,
+ sal_uInt16& nDuplicates,
+ sal_uInt16 nCurrentPos
+) const
+{
+ const vcl::I18nHelper& rI18nHelper = Application::GetSettings().GetUILocaleI18nHelper();
+
+ size_t nListCount = maItemList.size();
+
+ // try character code first
+ nDuplicates = GetItemCount( cSelectChar ); // return number of duplicates
+ if( nDuplicates )
+ {
+ for ( rPos = 0; rPos < nListCount; rPos++)
+ {
+ MenuItemData* pData = maItemList[ rPos ];
+ if ( pData->bEnabled && rI18nHelper.MatchMnemonic( pData->aText, cSelectChar ) )
+ {
+ if( nDuplicates > 1 && rPos == nCurrentPos )
+ continue; // select next entry with the same mnemonic
+ else
+ return pData;
+ }
+ }
+ }
+
+ // nothing found, try keycode instead
+ nDuplicates = GetItemCount( aKeyCode ); // return number of duplicates
+
+ if( nDuplicates )
+ {
+ char ascii = 0;
+ if( aKeyCode.GetCode() >= KEY_A && aKeyCode.GetCode() <= KEY_Z )
+ ascii = sal::static_int_cast<char>('A' + (aKeyCode.GetCode() - KEY_A));
+
+ for ( rPos = 0; rPos < nListCount; rPos++)
+ {
+ MenuItemData* pData = maItemList[ rPos ];
+ if ( pData->bEnabled )
+ {
+ sal_Int32 n = pData->aText.indexOf('~');
+ if ( n != -1 )
+ {
+ KeyCode mnKeyCode;
+ sal_Unicode mnUnicode = pData->aText[n+1];
+ Window* pDefWindow = ImplGetDefaultWindow();
+ if( ( pDefWindow
+ && pDefWindow->ImplGetFrame()->MapUnicodeToKeyCode( mnUnicode,
+ Application::GetSettings().GetUILanguageTag().getLanguageType(), mnKeyCode )
+ && aKeyCode.GetCode() == mnKeyCode.GetCode()
+ )
+ || ( ascii
+ && rI18nHelper.MatchMnemonic( pData->aText, ascii )
+ )
+ )
+ {
+ if( nDuplicates > 1 && rPos == nCurrentPos )
+ continue; // select next entry with the same mnemonic
+ else
+ return pData;
+ }
+ }
+ }
+ }
+ }
+
+ return NULL;
+}
+
+size_t MenuItemList::GetItemCount( sal_Unicode cSelectChar ) const
+{
+ // returns number of entries with same mnemonic
+ const vcl::I18nHelper& rI18nHelper = Application::GetSettings().GetUILocaleI18nHelper();
+
+ size_t nItems = 0;
+ for ( size_t nPos = maItemList.size(); nPos; )
+ {
+ MenuItemData* pData = maItemList[ --nPos ];
+ if ( pData->bEnabled && rI18nHelper.MatchMnemonic( pData->aText, cSelectChar ) )
+ nItems++;
+ }
+
+ return nItems;
+}
+
+size_t MenuItemList::GetItemCount( KeyCode aKeyCode ) const
+{
+ // returns number of entries with same mnemonic
+ // uses key codes instead of character codes
+ const vcl::I18nHelper& rI18nHelper = Application::GetSettings().GetUILocaleI18nHelper();
+ char ascii = 0;
+ if( aKeyCode.GetCode() >= KEY_A && aKeyCode.GetCode() <= KEY_Z )
+ ascii = sal::static_int_cast<char>('A' + (aKeyCode.GetCode() - KEY_A));
+
+ size_t nItems = 0;
+ for ( size_t nPos = maItemList.size(); nPos; )
+ {
+ MenuItemData* pData = maItemList[ --nPos ];
+ if ( pData->bEnabled )
+ {
+ sal_Int32 n = pData->aText.indexOf('~');
+ if (n != -1)
+ {
+ KeyCode mnKeyCode;
+ // if MapUnicodeToKeyCode fails or is unsupported we try the pure ascii mapping of the keycodes
+ // so we have working shortcuts when ascii mnemonics are used
+ Window* pDefWindow = ImplGetDefaultWindow();
+ if( ( pDefWindow
+ && pDefWindow->ImplGetFrame()->MapUnicodeToKeyCode( pData->aText[n+1],
+ Application::GetSettings().GetUILanguageTag().getLanguageType(), mnKeyCode )
+ && aKeyCode.GetCode() == mnKeyCode.GetCode()
+ )
+ || ( ascii
+ && rI18nHelper.MatchMnemonic( pData->aText, ascii )
+ )
+ )
+ nItems++;
+ }
+ }
+ }
+
+ return nItems;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/source/window/menuitemlist.hxx b/vcl/source/window/menuitemlist.hxx
new file mode 100644
index 000000000000..27f138efb4d1
--- /dev/null
+++ b/vcl/source/window/menuitemlist.hxx
@@ -0,0 +1,152 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <rsc/rsc-vcl-shared-types.hxx>
+#include <vcl/image.hxx>
+#include <vcl/keycod.hxx>
+#include <vcl/menu.hxx>
+
+#include <com/sun/star/i18n/XCharacterClassification.hpp>
+
+#include <vector>
+
+class SalMenuItem;
+
+struct MenuItemData
+{
+ sal_uInt16 nId; // SV Id
+ MenuItemType eType; // MenuItem-Type
+ MenuItemBits nBits; // MenuItem-Bits
+ Menu* pSubMenu; // Pointer to SubMenu
+ Menu* pAutoSubMenu; // Pointer to SubMenu from Resource
+ OUString aText; // Menu-Text
+ OUString aHelpText; // Help-String
+ OUString aTipHelpText; // TipHelp-String (eg, expanded filenames)
+ OUString aCommandStr; // CommandString
+ OUString aHelpCommandStr; // Help command string (to reference external help)
+ OString sIdent;
+ OString aHelpId; // Help-Id
+ sal_uLong nUserValue; // User value
+ Image aImage; // Image
+ vcl::KeyCode aAccelKey; // Accelerator-Key
+ bool bChecked; // Checked
+ bool bEnabled; // Enabled
+ bool bVisible; // Visible (note: this flag will not override MENU_FLAG_HIDEDISABLEDENTRIES when true)
+ bool bIsTemporary; // Temporary inserted ('No selection possible')
+ bool bMirrorMode;
+ long nItemImageAngle;
+ Size aSz; // only temporarily valid
+ OUString aAccessibleName; // accessible name
+ OUString aAccessibleDescription; // accessible description
+
+ SalMenuItem* pSalMenuItem; // access to native menu
+
+ MenuItemData()
+ : nId(0)
+ , eType(MENUITEM_DONTKNOW)
+ , nBits(0)
+ , pSubMenu(NULL)
+ , pAutoSubMenu(NULL)
+ , nUserValue(0)
+ , bChecked(false)
+ , bEnabled(false)
+ , bVisible(false)
+ , bIsTemporary(false)
+ , bMirrorMode(false)
+ , nItemImageAngle(0)
+ , pSalMenuItem(NULL)
+ {
+ }
+ MenuItemData( const OUString& rStr, const Image& rImage )
+ : nId(0)
+ , eType(MENUITEM_DONTKNOW)
+ , nBits(0)
+ , pSubMenu(NULL)
+ , pAutoSubMenu(NULL)
+ , aText(rStr)
+ , nUserValue(0)
+ , aImage(rImage)
+ , bChecked(false)
+ , bEnabled(false)
+ , bVisible(false)
+ , bIsTemporary(false)
+ , bMirrorMode(false)
+ , nItemImageAngle(0)
+ , pSalMenuItem(NULL)
+ {
+ }
+ ~MenuItemData();
+ bool HasCheck() const
+ {
+ return bChecked || ( nBits & ( MIB_RADIOCHECK | MIB_CHECKABLE | MIB_AUTOCHECK ) );
+ }
+};
+
+class MenuItemList
+{
+private:
+ typedef ::std::vector< MenuItemData* > MenuItemDataList_impl;
+ MenuItemDataList_impl maItemList;
+
+ css::uno::Reference< css::i18n::XCharacterClassification > xCharClass;
+
+public:
+ MenuItemList() {}
+ ~MenuItemList();
+
+ MenuItemData* Insert(
+ sal_uInt16 nId,
+ MenuItemType eType,
+ MenuItemBits nBits,
+ const OUString& rStr,
+ const Image& rImage,
+ Menu* pMenu,
+ size_t nPos,
+ const OString &rIdent
+ );
+ void InsertSeparator(const OString &rIdent, size_t nPos);
+ void Remove( size_t nPos );
+
+ MenuItemData* GetData( sal_uInt16 nSVId, size_t& rPos ) const;
+ MenuItemData* GetData( sal_uInt16 nSVId ) const
+ {
+ size_t nTemp;
+ return GetData( nSVId, nTemp );
+ }
+ MenuItemData* GetDataFromPos( size_t nPos ) const
+ {
+ return ( nPos < maItemList.size() ) ? maItemList[ nPos ] : NULL;
+ }
+
+ MenuItemData* SearchItem(
+ sal_Unicode cSelectChar,
+ vcl::KeyCode aKeyCode,
+ sal_uInt16& rPos,
+ sal_uInt16& nDuplicates,
+ sal_uInt16 nCurrentPos
+ ) const;
+ size_t GetItemCount( sal_Unicode cSelectChar ) const;
+ size_t GetItemCount( vcl::KeyCode aKeyCode ) const;
+ size_t size()
+ {
+ return maItemList.size();
+ }
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/source/window/menuwindow.cxx b/vcl/source/window/menuwindow.cxx
new file mode 100644
index 000000000000..0f0a8dd52f6a
--- /dev/null
+++ b/vcl/source/window/menuwindow.cxx
@@ -0,0 +1,161 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "menuwindow.hxx"
+#include "menuitemlist.hxx"
+
+#include <vcl/help.hxx>
+#include <vcl/menu.hxx>
+#include <vcl/settings.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/window.hxx>
+
+void MenuWindow::ImplInitMenuWindow(Window* pWin, bool bFont, bool bMenuBar)
+{
+ const StyleSettings& rStyleSettings = pWin->GetSettings().GetStyleSettings();
+
+ if ( bFont )
+ pWin->SetPointFont( rStyleSettings.GetMenuFont() );
+ if( bMenuBar )
+ {
+ const BitmapEx& rPersonaBitmap = Application::GetSettings().GetStyleSettings().GetPersonaHeader();
+ if ( !rPersonaBitmap.IsEmpty() )
+ {
+ Wallpaper aWallpaper( rPersonaBitmap );
+ aWallpaper.SetStyle( WALLPAPER_TOPRIGHT );
+ aWallpaper.SetColor( Application::GetSettings().GetStyleSettings().GetWorkspaceColor() );
+
+ pWin->SetBackground( aWallpaper );
+ pWin->SetPaintTransparent( false );
+ pWin->SetParentClipMode( 0 );
+ }
+ else if ( pWin->IsNativeControlSupported( CTRL_MENUBAR, PART_ENTIRE_CONTROL ) )
+ {
+ pWin->SetBackground(); // background will be drawn by NWF
+ }
+ else
+ {
+ Wallpaper aWallpaper;
+ aWallpaper.SetStyle( WALLPAPER_APPLICATIONGRADIENT );
+ pWin->SetBackground( aWallpaper );
+ pWin->SetPaintTransparent( false );
+ pWin->SetParentClipMode( 0 );
+ }
+ }
+ else
+ {
+ if( pWin->IsNativeControlSupported( CTRL_MENU_POPUP, PART_ENTIRE_CONTROL ) )
+ {
+ pWin->SetBackground(); // background will be drawn by NWF
+ }
+ else
+ pWin->SetBackground( Wallpaper( rStyleSettings.GetMenuColor() ) );
+ }
+
+ if ( bMenuBar )
+ pWin->SetTextColor( rStyleSettings.GetMenuBarTextColor() );
+ else
+ pWin->SetTextColor( rStyleSettings.GetMenuTextColor() );
+ pWin->SetTextFillColor();
+ pWin->SetLineColor();
+}
+
+static sal_uLong ImplChangeTipTimeout( sal_uLong nTimeout, Window *pWindow )
+{
+ AllSettings aAllSettings( pWindow->GetSettings() );
+ HelpSettings aHelpSettings( aAllSettings.GetHelpSettings() );
+ sal_uLong nRet = aHelpSettings.GetTipTimeout();
+ aHelpSettings.SetTipTimeout( nTimeout );
+ aAllSettings.SetHelpSettings( aHelpSettings );
+ pWindow->SetSettings( aAllSettings );
+ return nRet;
+}
+
+bool MenuWindow::ImplHandleHelpEvent(Window* pMenuWindow, Menu* pMenu, sal_uInt16 nHighlightedItem,
+ const HelpEvent& rHEvt, const Rectangle &rHighlightRect)
+{
+ if( ! pMenu )
+ return false;
+
+ bool bDone = false;
+ sal_uInt16 nId = 0;
+
+ if ( nHighlightedItem != ITEMPOS_INVALID )
+ {
+ MenuItemData* pItemData = pMenu->GetItemList()->GetDataFromPos( nHighlightedItem );
+ if ( pItemData )
+ nId = pItemData->nId;
+ }
+
+ if ( ( rHEvt.GetMode() & HELPMODE_BALLOON ) && pMenuWindow )
+ {
+ Point aPos;
+ if( rHEvt.KeyboardActivated() )
+ aPos = rHighlightRect.Center();
+ else
+ aPos = rHEvt.GetMousePosPixel();
+
+ Rectangle aRect( aPos, Size() );
+ if (!pMenu->GetHelpText(nId).isEmpty())
+ Help::ShowBalloon( pMenuWindow, aPos, pMenu->GetHelpText( nId ) );
+ else
+ {
+ // give user a chance to read the full filename
+ sal_uLong oldTimeout=ImplChangeTipTimeout( 60000, pMenuWindow );
+ // call always, even when strlen==0 to correctly remove tip
+ Help::ShowQuickHelp( pMenuWindow, aRect, pMenu->GetTipHelpText( nId ) );
+ ImplChangeTipTimeout( oldTimeout, pMenuWindow );
+ }
+ bDone = true;
+ }
+ else if ( ( rHEvt.GetMode() & HELPMODE_QUICK ) && pMenuWindow )
+ {
+ Point aPos = rHEvt.GetMousePosPixel();
+ Rectangle aRect( aPos, Size() );
+ // give user a chance to read the full filename
+ sal_uLong oldTimeout=ImplChangeTipTimeout( 60000, pMenuWindow );
+ // call always, even when strlen==0 to correctly remove tip
+ Help::ShowQuickHelp( pMenuWindow, aRect, pMenu->GetTipHelpText( nId ) );
+ ImplChangeTipTimeout( oldTimeout, pMenuWindow );
+ bDone = true;
+ }
+ else if ( rHEvt.GetMode() & (HELPMODE_CONTEXT | HELPMODE_EXTENDED) )
+ {
+ // is help in the application selected
+ Help* pHelp = Application::GetHelp();
+ if ( pHelp )
+ {
+ // is an id available, then call help with the id, otherwise
+ // use help-index
+ OUString aCommand = pMenu->GetItemCommand( nId );
+ OString aHelpId( pMenu->GetHelpId( nId ) );
+ if( aHelpId.isEmpty() )
+ aHelpId = OOO_HELP_INDEX;
+
+ if ( !aCommand.isEmpty() )
+ pHelp->Start( aCommand, NULL );
+ else
+ pHelp->Start( OStringToOUString( aHelpId, RTL_TEXTENCODING_UTF8 ), NULL );
+ }
+ bDone = true;
+ }
+ return bDone;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/source/window/menuwindow.hxx b/vcl/source/window/menuwindow.hxx
new file mode 100644
index 000000000000..9b2f099a5d57
--- /dev/null
+++ b/vcl/source/window/menuwindow.hxx
@@ -0,0 +1,49 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_VCL_SOURCE_WINDOW_MENUWINDOW_HXX
+#define INCLUDED_VCL_SOURCE_WINDOW_MENUWINDOW_HXX
+
+#include <sal/types.h>
+
+class HelpEvent;
+class Menu;
+class Rectangle;
+class Window;
+
+/** Common ancestor for MenuFloatingWindow and MenuBarWindow.
+
+The menu can be a floating window, or a menu bar. Even though this has
+'Window' in the name, it is not derived from the VCL's Window class, as the
+MenuFloatingWindow's or MenuBarWindow's already are VCL Windows.
+*/
+class MenuWindow
+{
+public:
+
+ /// Sets up some visual properties of the underlying window.
+ void ImplInitMenuWindow(Window* pWin, bool bFont, bool bMenuBar);
+
+ /// Show the appropriate help tooltip.
+ bool ImplHandleHelpEvent(Window* pMenuWindow, Menu* pMenu, sal_uInt16 nHighlightedItem,
+ const HelpEvent& rHEvt, const Rectangle &rHighlightRect);
+};
+
+#endif // INCLUDED_VCL_SOURCE_WINDOW_MENUWINDOW_HXX
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */