summaryrefslogtreecommitdiff
path: root/vcl/source/window/menu.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'vcl/source/window/menu.cxx')
-rw-r--r--vcl/source/window/menu.cxx6099
1 files changed, 6099 insertions, 0 deletions
diff --git a/vcl/source/window/menu.cxx b/vcl/source/window/menu.cxx
new file mode 100644
index 000000000000..e77eacb2fddf
--- /dev/null
+++ b/vcl/source/window/menu.cxx
@@ -0,0 +1,6099 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include "svsys.h"
+#include "vcl/salinst.hxx"
+#include "tools/list.hxx"
+#include "tools/debug.hxx"
+#include "tools/diagnose_ex.h"
+#include "vcl/svdata.hxx"
+#include "vcl/svapp.hxx"
+#include "vcl/mnemonic.hxx"
+#include "vcl/image.hxx"
+#include "vcl/event.hxx"
+#include "vcl/help.hxx"
+#include "vcl/svids.hrc"
+#include "vcl/floatwin.hxx"
+#include "vcl/wrkwin.hxx"
+#include "vcl/timer.hxx"
+#include "vcl/sound.hxx"
+#include "vcl/decoview.hxx"
+#include "vcl/bitmap.hxx"
+#include "tools/rc.h"
+#include "vcl/menu.hxx"
+#include "vcl/button.hxx"
+#include "vcl/gradient.hxx"
+#include "vcl/i18nhelp.hxx"
+#include "vcl/taskpanelist.hxx"
+#include "vcl/window.h"
+#include "vcl/controllayout.hxx"
+#include "vcl/toolbox.hxx"
+#include "tools/stream.hxx"
+#include "vcl/salmenu.hxx"
+#include "vcl/salframe.hxx"
+#include "vcl/dockingarea.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>
+#include <vcl/unowrap.hxx>
+
+#include <vcl/unohelp.hxx>
+#include <vcl/configsettings.hxx>
+
+#include "vcl/lazydelete.hxx"
+
+#include <map>
+
+namespace vcl
+{
+
+struct MenuLayoutData : public ControlLayoutData
+{
+ std::vector< USHORT > m_aLineItemIds;
+ std::vector< USHORT > m_aLineItemPositions;
+ std::map< USHORT, Rectangle > m_aVisibleItemBoundRects;
+};
+
+}
+
+using namespace ::com::sun::star;
+using namespace vcl;
+
+DBG_NAME( Menu )
+
+#define ITEMPOS_INVALID 0xFFFF
+
+#define EXTRASPACEY 2
+#define EXTRAITEMHEIGHT 4
+
+// document closer
+#define IID_DOCUMENTCLOSE 1
+
+#ifdef OS2
+
+#include <xwphook.h>
+
+// return TRUE if hilite should be executed: left mouse button down
+// or xwp mouse hook enabled
+static BOOL ImplHilite( const MouseEvent& rMEvt )
+{
+ static BOOL init = FALSE;
+ static HOOKCONFIG hc;
+
+ // read XWP settings at program startup
+ if (init == FALSE) {
+ BOOL rc;
+ ULONG cb = sizeof(HOOKCONFIG);
+ memset(&hc, 0, sizeof(HOOKCONFIG));
+ rc = PrfQueryProfileData( HINI_USER, INIAPP_XWPHOOK, INIKEY_HOOK_CONFIG,
+ &hc, &cb);
+ init = TRUE;
+ }
+ // check mouse left button
+ if (rMEvt.GetButtons() == MOUSE_LEFT)
+ return TRUE;
+ // return xwp flag
+ return hc.fSlidingMenus;
+}
+
+#endif
+
+static BOOL ImplAccelDisabled()
+{
+ // display of accelerator strings may be suppressed via configuration
+ static int nAccelDisabled = -1;
+
+ if( nAccelDisabled == -1 )
+ {
+ rtl::OUString aStr =
+ vcl::SettingsConfigItem::get()->
+ getValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Menu" ) ),
+ rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "SuppressAccelerators" ) ) );
+ nAccelDisabled = aStr.equalsIgnoreAsciiCaseAscii( "true" ) ? 1 : 0;
+ }
+ return (nAccelDisabled == 1) ? TRUE : FALSE;
+}
+
+struct MenuItemData
+{
+ USHORT nId; // SV Id
+ MenuItemType eType; // MenuItem-Type
+ MenuItemBits nBits; // MenuItem-Bits
+ Menu* pSubMenu; // Pointer auf das SubMenu
+ Menu* pAutoSubMenu; // Pointer auf SubMenu aus Resource
+ XubString aText; // Menu-Text
+ XubString aHelpText; // Help-String
+ XubString aTipHelpText; // TipHelp-String (eg, expanded filenames)
+ XubString aCommandStr; // CommandString
+ XubString aHelpCommandStr; // Help command string (to reference external help)
+ ULONG nHelpId; // Help-Id
+ 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; // nur temporaer gueltig
+ XubString aAccessibleName; // accessible name
+ XubString aAccessibleDescription; // accessible description
+
+ SalMenuItem* pSalMenuItem; // access to native menu
+
+ MenuItemData() :
+ pSalMenuItem ( NULL )
+ {}
+ MenuItemData( const XubString& rStr, const Image& rImage ) :
+ aText( rStr ),
+ aImage( rImage ),
+ pSalMenuItem ( NULL )
+ {}
+ ~MenuItemData();
+ bool HasCheck()
+ {
+ 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 : public List
+{
+private:
+ uno::Reference< i18n::XCharacterClassification > xCharClass;
+
+
+public:
+ MenuItemList() : List( 16, 4 ) {}
+ ~MenuItemList();
+
+ MenuItemData* Insert( USHORT nId, MenuItemType eType, MenuItemBits nBits,
+ const XubString& rStr, const Image& rImage,
+ Menu* pMenu, USHORT nPos );
+ void InsertSeparator( USHORT nPos );
+ void Remove( USHORT nPos );
+
+
+ MenuItemData* GetData( USHORT nSVId, USHORT& rPos ) const;
+ MenuItemData* GetData( USHORT nSVId ) const
+ { USHORT nTemp; return GetData( nSVId, nTemp ); }
+ MenuItemData* GetDataFromPos( ULONG nPos ) const
+ { return (MenuItemData*)List::GetObject( nPos ); }
+
+ MenuItemData* SearchItem( xub_Unicode cSelectChar, KeyCode aKeyCode, USHORT& rPos, USHORT& nDuplicates, USHORT nCurrentPos ) const;
+ USHORT GetItemCount( xub_Unicode cSelectChar ) const;
+ USHORT GetItemCount( KeyCode aKeyCode ) const;
+
+ uno::Reference< i18n::XCharacterClassification > GetCharClass() const;
+};
+
+
+
+MenuItemList::~MenuItemList()
+{
+ for ( ULONG n = Count(); n; )
+ {
+ MenuItemData* pData = GetDataFromPos( --n );
+ delete pData;
+ }
+}
+
+MenuItemData* MenuItemList::Insert( USHORT nId, MenuItemType eType,
+ MenuItemBits nBits,
+ const XubString& rStr, const Image& rImage,
+ Menu* pMenu, USHORT nPos )
+{
+ MenuItemData* pData = new MenuItemData( rStr, rImage );
+ pData->nId = nId;
+ pData->eType = eType;
+ pData->nBits = nBits;
+ pData->pSubMenu = NULL;
+ pData->pAutoSubMenu = NULL;
+ pData->nHelpId = 0;
+ 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 );
+
+ List::Insert( (void*)pData, nPos );
+ return pData;
+}
+
+void MenuItemList::InsertSeparator( USHORT nPos )
+{
+ MenuItemData* pData = new MenuItemData;
+ pData->nId = 0;
+ pData->eType = MENUITEM_SEPARATOR;
+ pData->nBits = 0;
+ pData->pSubMenu = NULL;
+ pData->pAutoSubMenu = NULL;
+ pData->nHelpId = 0;
+ 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 = XubString();
+ aSalMIData.aImage = Image();
+
+ // Native-support: returns NULL if not supported
+ pData->pSalMenuItem = ImplGetSVData()->mpDefInst->CreateMenuItem( &aSalMIData );
+
+ List::Insert( (void*)pData, nPos );
+}
+
+void MenuItemList::Remove( USHORT nPos )
+{
+ MenuItemData* pData = (MenuItemData*)List::Remove( (ULONG)nPos );
+ if ( pData )
+ delete pData;
+}
+
+MenuItemData* MenuItemList::GetData( USHORT nSVId, USHORT& rPos ) const
+{
+ rPos = 0;
+ MenuItemData* pData = (MenuItemData*)GetObject( rPos );
+ while ( pData )
+ {
+ if ( pData->nId == nSVId )
+ return pData;
+
+ rPos++;
+ pData = (MenuItemData*)GetObject( rPos );
+ }
+
+ return NULL;
+}
+
+MenuItemData* MenuItemList::SearchItem( xub_Unicode cSelectChar, KeyCode aKeyCode, USHORT& rPos, USHORT& nDuplicates, USHORT nCurrentPos ) const
+{
+ const vcl::I18nHelper& rI18nHelper = Application::GetSettings().GetUILocaleI18nHelper();
+
+ USHORT nListCount = (USHORT)Count();
+
+ // try character code first
+ nDuplicates = GetItemCount( cSelectChar ); // return number of duplicates
+ if( nDuplicates )
+ {
+ for ( rPos = 0; rPos < nListCount; rPos++)
+ {
+ MenuItemData* pData = GetDataFromPos( 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 = GetDataFromPos( rPos );
+ if ( pData->bEnabled )
+ {
+ USHORT n = pData->aText.Search( '~' );
+ if ( n != STRING_NOTFOUND )
+ {
+ KeyCode mnKeyCode;
+ xub_Unicode mnUnicode = pData->aText.GetChar(n+1);
+ Window* pDefWindow = ImplGetDefaultWindow();
+ if( (pDefWindow && pDefWindow->ImplGetFrame()->MapUnicodeToKeyCode( mnUnicode, Application::GetSettings().GetUILanguage(), 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;
+}
+
+USHORT MenuItemList::GetItemCount( xub_Unicode cSelectChar ) const
+{
+ // returns number of entries with same mnemonic
+ const vcl::I18nHelper& rI18nHelper = Application::GetSettings().GetUILocaleI18nHelper();
+
+ USHORT nItems = 0, nPos;
+ for ( nPos = (USHORT)Count(); nPos; )
+ {
+ MenuItemData* pData = GetDataFromPos( --nPos );
+ if ( pData->bEnabled && rI18nHelper.MatchMnemonic( pData->aText, cSelectChar ) )
+ nItems++;
+ }
+
+ return nItems;
+}
+
+USHORT 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));
+
+ USHORT nItems = 0, nPos;
+ for ( nPos = (USHORT)Count(); nPos; )
+ {
+ MenuItemData* pData = GetDataFromPos( --nPos );
+ if ( pData->bEnabled )
+ {
+ USHORT n = pData->aText.Search( '~' );
+ if ( n != STRING_NOTFOUND )
+ {
+ 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.GetChar(n+1), Application::GetSettings().GetUILanguage(), mnKeyCode )
+ && aKeyCode.GetCode() == mnKeyCode.GetCode())
+ || ( ascii && rI18nHelper.MatchMnemonic( pData->aText, ascii ) ) )
+ nItems++;
+ }
+ }
+ }
+
+ return nItems;
+}
+
+uno::Reference< i18n::XCharacterClassification > MenuItemList::GetCharClass() const
+{
+ if ( !xCharClass.is() )
+ ((MenuItemList*)this)->xCharClass = vcl::unohelper::CreateCharacterClassification();
+ return xCharClass;
+}
+
+
+
+// ----------------------
+// - MenuFloatingWindow -
+// ----------------------
+
+class MenuFloatingWindow : public FloatingWindow
+{
+ friend void Menu::ImplFillLayoutData() const;
+ friend Menu::~Menu();
+
+private:
+ Menu* pMenu;
+ PopupMenu* pActivePopup;
+ Timer aHighlightChangedTimer;
+ Timer aSubmenuCloseTimer;
+ Timer aScrollTimer;
+ ULONG nSaveFocusId;
+// long nStartY;
+ USHORT nHighlightedItem; // gehighlightetes/selektiertes Item
+ USHORT nMBDownPos;
+ USHORT nScrollerHeight;
+ USHORT nFirstEntry;
+ USHORT nBorder;
+ USHORT nPosInParent;
+ BOOL bInExecute;
+
+ BOOL bScrollMenu;
+ BOOL bScrollUp;
+ BOOL bScrollDown;
+ BOOL bIgnoreFirstMove;
+ BOOL bKeyInput;
+
+ DECL_LINK( PopupEnd, FloatingWindow* );
+ DECL_LINK( HighlightChanged, Timer* );
+ DECL_LINK( SubmenuClose, Timer* );
+ DECL_LINK( AutoScroll, Timer* );
+ DECL_LINK( ShowHideListener, VclWindowEvent* );
+
+ void StateChanged( StateChangedType nType );
+ void DataChanged( const DataChangedEvent& rDCEvt );
+protected:
+ Region ImplCalcClipRegion( BOOL bIncludeLogo = TRUE ) const;
+ void ImplInitClipRegion();
+ 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( USHORT nPos );
+
+public:
+ MenuFloatingWindow( Menu* pMenu, Window* pParent, WinBits nStyle );
+ ~MenuFloatingWindow();
+
+ void doShutdown();
+
+ virtual void MouseMove( const MouseEvent& rMEvt );
+ virtual void MouseButtonDown( const MouseEvent& rMEvt );
+ virtual void MouseButtonUp( const MouseEvent& rMEvt );
+ virtual void KeyInput( const KeyEvent& rKEvent );
+ virtual void Command( const CommandEvent& rCEvt );
+ virtual void Paint( const Rectangle& rRect );
+ virtual void RequestHelp( const HelpEvent& rHEvt );
+ virtual void Resize();
+
+ void SetFocusId( ULONG nId ) { nSaveFocusId = nId; }
+ ULONG GetFocusId() const { return nSaveFocusId; }
+
+ void EnableScrollMenu( BOOL b );
+ BOOL IsScrollMenu() const { return bScrollMenu; }
+ USHORT GetScrollerHeight() const { return nScrollerHeight; }
+
+ void Execute();
+ void StopExecute( ULONG nFocusId = 0 );
+ void EndExecute();
+ void EndExecute( USHORT nSelectId );
+
+ PopupMenu* GetActivePopup() const { return pActivePopup; }
+ void KillActivePopup( PopupMenu* pThisOnly = NULL );
+
+ void HighlightItem( USHORT nPos, BOOL bHighlight );
+ void ChangeHighlightItem( USHORT n, BOOL bStartPopupTimer );
+ USHORT GetHighlightedItem() const { return nHighlightedItem; }
+
+ void SetPosInParent( USHORT nPos ) { nPosInParent = nPos; }
+ USHORT GetPosInParent() const { return nPosInParent; }
+
+ virtual ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible > CreateAccessible();
+};
+
+// To get the transparent mouse-over look, the closer is actually a toolbox
+// overload DataChange to handle style changes correctly
+class DecoToolBox : public ToolBox
+{
+ long lastSize;
+ Size maMinSize;
+
+ using Window::ImplInit;
+public:
+ DecoToolBox( Window* pParent, WinBits nStyle = 0 );
+ DecoToolBox( Window* pParent, const ResId& rResId );
+ void ImplInit();
+
+ void DataChanged( const DataChangedEvent& rDCEvt );
+
+ void SetImages( long nMaxHeight = 0, bool bForce = false );
+
+ void calcMinSize();
+ Size getMinSize();
+
+ Image maImage;
+ Image maImageHC;
+};
+
+DecoToolBox::DecoToolBox( Window* pParent, WinBits nStyle ) :
+ ToolBox( pParent, nStyle )
+{
+ ImplInit();
+}
+DecoToolBox::DecoToolBox( Window* pParent, const ResId& rResId ) :
+ ToolBox( pParent, rResId )
+{
+ ImplInit();
+}
+
+void DecoToolBox::ImplInit()
+{
+ lastSize = -1;
+ calcMinSize();
+}
+
+void DecoToolBox::DataChanged( const DataChangedEvent& rDCEvt )
+{
+ Window::DataChanged( rDCEvt );
+
+ if ( rDCEvt.GetFlags() & SETTINGS_STYLE )
+ {
+ calcMinSize();
+ SetBackground();
+ SetImages( 0, true);
+ }
+}
+
+void DecoToolBox::calcMinSize()
+{
+ ToolBox aTbx( GetParent() );
+ if( GetItemCount() == 0 )
+ {
+ ResMgr* pResMgr = ImplGetResMgr();
+
+ Bitmap aBitmap;
+ if( pResMgr )
+ aBitmap = Bitmap( ResId( SV_RESID_BITMAP_CLOSEDOC, *pResMgr ) );
+ aTbx.InsertItem( IID_DOCUMENTCLOSE, Image( aBitmap ) );
+ }
+ else
+ {
+ USHORT nItems = GetItemCount();
+ for( USHORT i = 0; i < nItems; i++ )
+ {
+ USHORT nId = GetItemId( i );
+ aTbx.InsertItem( nId, GetItemImage( nId ) );
+ }
+ }
+ aTbx.SetOutStyle( TOOLBOX_STYLE_FLAT );
+ maMinSize = aTbx.CalcWindowSizePixel();
+}
+
+Size DecoToolBox::getMinSize()
+{
+ return maMinSize;
+}
+
+void DecoToolBox::SetImages( long nMaxHeight, bool bForce )
+{
+ long border = getMinSize().Height() - maImage.GetSizePixel().Height();
+
+ if( !nMaxHeight && lastSize != -1 )
+ nMaxHeight = lastSize + border; // don't change anything if called with 0
+
+ if( nMaxHeight < getMinSize().Height() )
+ nMaxHeight = getMinSize().Height();
+
+ if( (lastSize != nMaxHeight - border) || bForce )
+ {
+ lastSize = nMaxHeight - border;
+
+ Color aEraseColor( 255, 255, 255, 255 );
+ BitmapEx aBmpExDst( maImage.GetBitmapEx() );
+ BitmapEx aBmpExSrc( GetSettings().GetStyleSettings().GetHighContrastMode() ?
+ maImageHC.GetBitmapEx() : aBmpExDst );
+
+ aEraseColor.SetTransparency( 255 );
+ aBmpExDst.Erase( aEraseColor );
+ aBmpExDst.SetSizePixel( Size( lastSize, lastSize ) );
+
+ Rectangle aSrcRect( Point(0,0), maImage.GetSizePixel() );
+ Rectangle aDestRect( Point((lastSize - maImage.GetSizePixel().Width())/2,
+ (lastSize - maImage.GetSizePixel().Height())/2 ),
+ maImage.GetSizePixel() );
+
+
+ aBmpExDst.CopyPixel( aDestRect, aSrcRect, &aBmpExSrc );
+ SetItemImage( IID_DOCUMENTCLOSE, Image( aBmpExDst ) );
+ }
+}
+
+
+// Eine Basicklasse fuer beide (wegen pActivePopup, Timer, ...) waere nett,
+// aber dann musste eine 'Container'-Klasse gemacht werden, da von
+// unterschiedlichen Windows abgeleitet...
+// In den meisten Funktionen muessen dann sowieso Sonderbehandlungen fuer
+// MenuBar, PopupMenu gemacht werden, also doch zwei verschiedene Klassen.
+
+class MenuBarWindow : public Window
+{
+ friend class MenuBar;
+ friend class Menu;
+
+private:
+ struct AddButtonEntry
+ {
+ USHORT m_nId;
+ Link m_aSelectLink;
+ Link m_aHighlightLink;
+
+ AddButtonEntry() : m_nId( 0 ) {}
+ };
+
+ Menu* pMenu;
+ PopupMenu* pActivePopup;
+ USHORT nHighlightedItem;
+ ULONG nSaveFocusId;
+ BOOL mbAutoPopup;
+ BOOL bIgnoreFirstMove;
+ BOOL bStayActive;
+
+ DecoToolBox aCloser;
+ PushButton aFloatBtn;
+ PushButton aHideBtn;
+
+ std::map< USHORT, AddButtonEntry > m_aAddButtons;
+
+ void HighlightItem( USHORT nPos, BOOL bHighlight );
+ void ChangeHighlightItem( USHORT n, BOOL bSelectPopupEntry, BOOL bAllowRestoreFocus = TRUE, BOOL bDefaultToDocument = TRUE );
+
+ USHORT ImplFindEntry( const Point& rMousePos ) const;
+ void ImplCreatePopup( BOOL bPreSelectFirst );
+ BOOL ImplHandleKeyEvent( const KeyEvent& rKEvent, BOOL bFromMenu = TRUE );
+ Rectangle ImplGetItemRect( USHORT nPos );
+
+ void ImplInitStyleSettings();
+
+ DECL_LINK( CloserHdl, PushButton* );
+ DECL_LINK( FloatHdl, PushButton* );
+ DECL_LINK( HideHdl, PushButton* );
+ DECL_LINK( ToolboxEventHdl, VclWindowEvent* );
+ DECL_LINK( ShowHideListener, VclWindowEvent* );
+
+ void StateChanged( StateChangedType nType );
+ void DataChanged( const DataChangedEvent& rDCEvt );
+ void LoseFocus();
+ void GetFocus();
+
+public:
+ MenuBarWindow( Window* pParent );
+ ~MenuBarWindow();
+
+ void ShowButtons( BOOL bClose, BOOL bFloat, BOOL bHide );
+
+ virtual void MouseMove( const MouseEvent& rMEvt );
+ virtual void MouseButtonDown( const MouseEvent& rMEvt );
+ virtual void MouseButtonUp( const MouseEvent& rMEvt );
+ virtual void KeyInput( const KeyEvent& rKEvent );
+ virtual void Paint( const Rectangle& rRect );
+ virtual void Resize();
+ virtual void RequestHelp( const HelpEvent& rHEvt );
+
+ void SetFocusId( ULONG nId ) { nSaveFocusId = nId; }
+ ULONG GetFocusId() const { return nSaveFocusId; }
+
+ void SetMenu( MenuBar* pMenu );
+ void KillActivePopup();
+ PopupMenu* GetActivePopup() const { return pActivePopup; }
+ void PopupClosed( Menu* pMenu );
+ USHORT GetHighlightedItem() const { return nHighlightedItem; }
+ virtual ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible > CreateAccessible();
+
+ void SetAutoPopup( BOOL bAuto ) { mbAutoPopup = bAuto; }
+ void ImplLayoutChanged();
+ Size MinCloseButtonSize();
+
+ // add an arbitrary button to the menubar (will appear next to closer)
+ USHORT AddMenuBarButton( const Image&, const Link&, const String&, USHORT nPos );
+ void SetMenuBarButtonHighlightHdl( USHORT nId, const Link& );
+ Rectangle GetMenuBarButtonRectPixel( USHORT nId );
+ void RemoveMenuBarButton( USHORT nId );
+ bool HandleMenuButtonEvent( USHORT i_nButtonId );
+};
+
+static void ImplAddNWFSeparator( Window *pThis, const MenubarValue& rMenubarValue )
+{
+ // add a separator if
+ // - we have an adjacent docking area
+ // - and if toolbars would draw them as well (mbDockingAreaSeparateTB must not be set, see dockingarea.cxx)
+ if( rMenubarValue.maTopDockingAreaHeight && !ImplGetSVData()->maNWFData.mbDockingAreaSeparateTB )
+ {
+ // note: the menubar only provides the upper (dark) half of it, the rest (bright part) is drawn by the docking area
+
+ pThis->SetLineColor( pThis->GetSettings().GetStyleSettings().GetSeparatorColor() );
+ Point aPt;
+ Rectangle aRect( aPt, pThis->GetOutputSizePixel() );
+ pThis->DrawLine( aRect.BottomLeft(), aRect.BottomRight() );
+ }
+}
+
+static void ImplSetMenuItemData( MenuItemData* pData )
+{
+ // Daten umsetzen
+ if ( !pData->aImage )
+ pData->eType = MENUITEM_STRING;
+ else if ( !pData->aText.Len() )
+ pData->eType = MENUITEM_IMAGE;
+ else
+ pData->eType = MENUITEM_STRINGIMAGE;
+}
+
+static ULONG ImplChangeTipTimeout( ULONG nTimeout, Window *pWindow )
+{
+ AllSettings aAllSettings( pWindow->GetSettings() );
+ HelpSettings aHelpSettings( aAllSettings.GetHelpSettings() );
+ ULONG nRet = aHelpSettings.GetTipTimeout();
+ aHelpSettings.SetTipTimeout( nTimeout );
+ aAllSettings.SetHelpSettings( aHelpSettings );
+ pWindow->SetSettings( aAllSettings );
+ return nRet;
+}
+
+static BOOL ImplHandleHelpEvent( Window* pMenuWindow, Menu* pMenu, USHORT nHighlightedItem, const HelpEvent& rHEvt, const Rectangle &rHighlightRect )
+{
+ if( ! pMenu )
+ return FALSE;
+
+ BOOL bDone = FALSE;
+ USHORT 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 ).Len() )
+ Help::ShowBalloon( pMenuWindow, aPos, pMenu->GetHelpText( nId ) );
+ else
+ {
+ // give user a chance to read the full filename
+ 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
+ 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) )
+ {
+ // Ist eine Hilfe in die Applikation selektiert
+ Help* pHelp = Application::GetHelp();
+ if ( pHelp )
+ {
+ // Ist eine ID vorhanden, dann Hilfe mit der ID aufrufen, sonst
+ // den Hilfe-Index
+ String aCommand = pMenu->GetItemCommand( nId );
+ ULONG nHelpId = pMenu->GetHelpId( nId );
+
+ if ( aCommand.Len() )
+ pHelp->Start( aCommand, NULL );
+ else if ( nHelpId )
+ pHelp->Start( nHelpId, NULL );
+ else
+ pHelp->Start( OOO_HELP_INDEX, NULL );
+ }
+ bDone = TRUE;
+ }
+ return bDone;
+}
+
+static int ImplGetTopDockingAreaHeight( Window *pWindow )
+{
+ // find docking area that is top aligned and return its height
+ // note: dockingareas are direct children of the SystemWindow
+ int height=0;
+ BOOL bDone = FALSE;
+ if( pWindow->ImplGetFrameWindow() )
+ {
+ Window *pWin = pWindow->ImplGetFrameWindow()->GetWindow( WINDOW_FIRSTCHILD); //mpWindowImpl->mpFirstChild;
+ while( pWin && !bDone )
+ {
+ if( pWin->IsSystemWindow() )
+ {
+ pWin = pWin->GetWindow( WINDOW_FIRSTCHILD); //mpWindowImpl->mpFirstChild;
+ while( pWin && !bDone )
+ {
+ DockingAreaWindow *pDockingArea = dynamic_cast< DockingAreaWindow* >( pWin );
+ if( pDockingArea && pDockingArea->GetAlign() == WINDOWALIGN_TOP )
+ {
+ bDone = TRUE;
+ if( pDockingArea->IsVisible() )
+ height = pDockingArea->GetOutputSizePixel().Height();
+ }
+ else
+ pWin = pWin->GetWindow( WINDOW_NEXT ); //mpWindowImpl->mpNext;
+ }
+
+ }
+ else
+ pWin = pWin->GetWindow( WINDOW_NEXT ); //mpWindowImpl->mpNext;
+ }
+ }
+ return height;
+}
+
+Menu::Menu()
+{
+ DBG_CTOR( Menu, NULL );
+ bIsMenuBar = FALSE;
+ ImplInit();
+}
+
+// this constructor makes sure we're creating the native menu
+// with the correct type (ie, MenuBar vs. PopupMenu)
+Menu::Menu( BOOL bMenubar )
+{
+ DBG_CTOR( Menu, NULL );
+ bIsMenuBar = bMenubar;
+ ImplInit();
+}
+
+Menu::~Menu()
+{
+ DBG_DTOR( Menu, NULL );
+
+ vcl::LazyDeletor<Menu>::Undelete( this );
+
+ ImplCallEventListeners( VCLEVENT_OBJECT_DYING, ITEMPOS_INVALID );
+
+ // at the window free the reference to the accessible component
+ // and make sure the MenuFloatingWindow knows about our destruction
+ if ( pWindow )
+ {
+ MenuFloatingWindow* pFloat = (MenuFloatingWindow*)pWindow;
+ if( pFloat->pMenu == this )
+ pFloat->pMenu = NULL;
+ pWindow->SetAccessible( ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible >() );
+ }
+
+ // dispose accessible components
+ if ( mxAccessible.is() )
+ {
+ ::com::sun::star::uno::Reference< ::com::sun::star::lang::XComponent> xComponent( mxAccessible, ::com::sun::star::uno::UNO_QUERY );
+ if ( xComponent.is() )
+ xComponent->dispose();
+ }
+
+ if ( nEventId )
+ Application::RemoveUserEvent( nEventId );
+
+ // Notify deletion of this menu
+ ImplMenuDelData* pDelData = mpFirstDel;
+ while ( pDelData )
+ {
+ pDelData->mpMenu = NULL;
+ pDelData = pDelData->mpNext;
+ }
+
+ bKilled = TRUE;
+
+ delete pItemList;
+ delete pLogo;
+ delete mpLayoutData;
+
+ // Native-support: destroy SalMenu
+ ImplSetSalMenu( NULL );
+}
+
+void Menu::doLazyDelete()
+{
+ vcl::LazyDeletor<Menu>::Delete( this );
+}
+
+void Menu::ImplInit()
+{
+ mnHighlightedItemPos = ITEMPOS_INVALID;
+ mpSalMenu = NULL;
+ nMenuFlags = MENU_FLAG_SHOWCHECKIMAGES;
+ nDefaultItem = 0;
+ //bIsMenuBar = FALSE; // this is now set in the ctor, must not be changed here!!!
+ nSelectedId = 0;
+ pItemList = new MenuItemList;
+ pLogo = NULL;
+ pStartedFrom = NULL;
+ pWindow = NULL;
+ nEventId = 0;
+ bCanceled = FALSE;
+ bInCallback = FALSE;
+ bKilled = FALSE;
+ mpLayoutData = NULL;
+ mpFirstDel = NULL; // Dtor notification list
+ // Native-support: returns NULL if not supported
+ mpSalMenu = ImplGetSVData()->mpDefInst->CreateMenu( bIsMenuBar );
+}
+
+Menu* Menu::ImplGetStartedFrom() const
+{
+ return pStartedFrom;
+}
+
+void Menu::ImplLoadRes( const ResId& rResId )
+{
+ ResMgr* pMgr = rResId.GetResMgr();
+ if( ! pMgr )
+ return;
+
+ rResId.SetRT( RSC_MENU );
+ GetRes( rResId );
+
+ ULONG nObjMask = ReadLongRes();
+
+ if( nObjMask & RSC_MENU_ITEMS )
+ {
+ ULONG nObjFollows = ReadLongRes();
+ // MenuItems einfuegen
+ for( ULONG i = 0; i < nObjFollows; i++ )
+ {
+ InsertItem( ResId( (RSHEADER_TYPE*)GetClassRes(), *pMgr ) );
+ IncrementRes( GetObjSizeRes( (RSHEADER_TYPE*)GetClassRes() ) );
+ }
+ }
+
+ if( nObjMask & RSC_MENU_TEXT )
+ {
+ if( bIsMenuBar ) // Kein Titel im Menubar
+ ReadStringRes();
+ else
+ aTitleText = ReadStringRes();
+ }
+ if( nObjMask & RSC_MENU_DEFAULTITEMID )
+ SetDefaultItem( sal::static_int_cast<USHORT>(ReadLongRes()) );
+}
+
+void Menu::CreateAutoMnemonics()
+{
+ MnemonicGenerator aMnemonicGenerator;
+ ULONG n;
+ for ( n = 0; n < pItemList->Count(); n++ )
+ {
+ MenuItemData* pData = pItemList->GetDataFromPos(n);
+ if ( ! (pData->nBits & MIB_NOSELECT ) )
+ aMnemonicGenerator.RegisterMnemonic( pData->aText );
+ }
+ for ( n = 0; n < pItemList->Count(); n++ )
+ {
+ MenuItemData* pData = pItemList->GetDataFromPos(n);
+ if ( ! (pData->nBits & MIB_NOSELECT ) )
+ aMnemonicGenerator.CreateMnemonic( pData->aText );
+ }
+}
+
+void Menu::Activate()
+{
+ bInCallback = TRUE;
+
+ ImplMenuDelData aDelData( this );
+
+ ImplCallEventListeners( VCLEVENT_MENU_ACTIVATE, ITEMPOS_INVALID );
+
+ if( !aDelData.isDeleted() )
+ {
+ if ( !aActivateHdl.Call( this ) )
+ {
+ if( !aDelData.isDeleted() )
+ {
+ Menu* pStartMenu = ImplGetStartMenu();
+ if ( pStartMenu && ( pStartMenu != this ) )
+ {
+ pStartMenu->bInCallback = TRUE;
+ // MT 11/01: Call EventListener here? I don't know...
+ pStartMenu->aActivateHdl.Call( this );
+ pStartMenu->bInCallback = FALSE;
+ }
+ }
+ }
+ bInCallback = FALSE;
+ }
+}
+
+void Menu::Deactivate()
+{
+ for ( USHORT n = (USHORT)pItemList->Count(); n; )
+ {
+ MenuItemData* pData = pItemList->GetDataFromPos( --n );
+ if ( pData->bIsTemporary )
+ pItemList->Remove( n );
+ }
+
+ bInCallback = TRUE;
+
+ ImplMenuDelData aDelData( this );
+
+ Menu* pStartMenu = ImplGetStartMenu();
+ ImplCallEventListeners( VCLEVENT_MENU_DEACTIVATE, ITEMPOS_INVALID );
+
+ if( !aDelData.isDeleted() )
+ {
+ if ( !aDeactivateHdl.Call( this ) )
+ {
+ if( !aDelData.isDeleted() )
+ {
+ if ( pStartMenu && ( pStartMenu != this ) )
+ {
+ pStartMenu->bInCallback = TRUE;
+ pStartMenu->aDeactivateHdl.Call( this );
+ pStartMenu->bInCallback = FALSE;
+ }
+ }
+ }
+ }
+
+ if( !aDelData.isDeleted() )
+ {
+ bInCallback = FALSE;
+
+ if ( this == pStartMenu )
+ GetpApp()->HideHelpStatusText();
+ }
+}
+
+void Menu::Highlight()
+{
+ ImplMenuDelData aDelData( this );
+
+ Menu* pStartMenu = ImplGetStartMenu();
+ if ( !aHighlightHdl.Call( this ) && !aDelData.isDeleted() )
+ {
+ if ( pStartMenu && ( pStartMenu != this ) )
+ pStartMenu->aHighlightHdl.Call( this );
+ }
+
+ if ( !aDelData.isDeleted() && GetCurItemId() )
+ GetpApp()->ShowHelpStatusText( GetHelpText( GetCurItemId() ) );
+}
+
+void Menu::ImplSelect()
+{
+ MenuItemData* pData = GetItemList()->GetData( nSelectedId );
+ if ( pData && (pData->nBits & MIB_AUTOCHECK) )
+ {
+ BOOL bChecked = IsItemChecked( nSelectedId );
+ if ( pData->nBits & MIB_RADIOCHECK )
+ {
+ if ( !bChecked )
+ CheckItem( nSelectedId, TRUE );
+ }
+ else
+ CheckItem( nSelectedId, !bChecked );
+ }
+
+ // Select rufen
+ ImplSVData* pSVData = ImplGetSVData();
+ pSVData->maAppData.mpActivePopupMenu = NULL; // Falls neues Execute im Select()
+ Application::PostUserEvent( nEventId, LINK( this, Menu, ImplCallSelect ) );
+}
+
+void Menu::Select()
+{
+ ImplMenuDelData aDelData( this );
+
+ ImplCallEventListeners( VCLEVENT_MENU_SELECT, GetItemPos( GetCurItemId() ) );
+ if ( !aDelData.isDeleted() && !aSelectHdl.Call( this ) )
+ {
+ if( !aDelData.isDeleted() )
+ {
+ Menu* pStartMenu = ImplGetStartMenu();
+ if ( pStartMenu && ( pStartMenu != this ) )
+ {
+ pStartMenu->nSelectedId = nSelectedId;
+ pStartMenu->aSelectHdl.Call( this );
+ }
+ }
+ }
+}
+
+void Menu::ImplSelectWithStart( Menu* pSMenu )
+{
+ Menu* pOldStartedFrom = pStartedFrom;
+ pStartedFrom = pSMenu;
+ Menu* pOldStartedStarted = pOldStartedFrom ? pOldStartedFrom->pStartedFrom : NULL;
+ Select();
+ if( pOldStartedFrom )
+ pOldStartedFrom->pStartedFrom = pOldStartedStarted;
+ pStartedFrom = pOldStartedFrom;
+}
+
+void Menu::RequestHelp( const HelpEvent& )
+{
+}
+
+void Menu::ImplCallEventListeners( ULONG nEvent, USHORT nPos )
+{
+ ImplMenuDelData aDelData( this );
+
+ VclMenuEvent aEvent( this, nEvent, nPos );
+
+ // This is needed by atk accessibility bridge
+ if ( nEvent == VCLEVENT_MENU_HIGHLIGHT )
+ {
+ ImplGetSVData()->mpApp->ImplCallEventListeners( &aEvent );
+ }
+
+ if ( !aDelData.isDeleted() && !maEventListeners.empty() )
+ maEventListeners.Call( &aEvent );
+
+ if( !aDelData.isDeleted() )
+ {
+ Menu* pMenu = this;
+ while ( pMenu )
+ {
+ if ( !maChildEventListeners.empty() )
+ maChildEventListeners.Call( &aEvent );
+
+ if( aDelData.isDeleted() )
+ break;
+
+ pMenu = ( pMenu->pStartedFrom != pMenu ) ? pMenu->pStartedFrom : NULL;
+ }
+ }
+}
+
+void Menu::AddEventListener( const Link& rEventListener )
+{
+ maEventListeners.push_back( rEventListener );
+}
+
+void Menu::RemoveEventListener( const Link& rEventListener )
+{
+ maEventListeners.remove( rEventListener );
+}
+
+// -----------------------------------------------------------------------
+
+//void Menu::AddChildEventListener( const Link& rEventListener )
+//{
+// mpDummy4_WindowChildEventListeners->push_back( rEventListener );
+//}
+
+// -----------------------------------------------------------------------
+
+//void Menu::RemoveChildEventListener( const Link& rEventListener )
+//{
+// mpDummy4_WindowChildEventListeners->remove( rEventListener );
+//}
+
+void Menu::InsertItem( USHORT nItemId, const XubString& rStr, MenuItemBits nItemBits, USHORT nPos )
+{
+ DBG_ASSERT( nItemId, "Menu::InsertItem(): ItemId == 0" );
+ DBG_ASSERT( GetItemPos( nItemId ) == MENU_ITEM_NOTFOUND,
+ "Menu::InsertItem(): ItemId already exists" );
+
+ // if Position > ItemCount, append
+ if ( nPos >= (USHORT)pItemList->Count() )
+ nPos = MENU_APPEND;
+
+ // put Item in MenuItemList
+ MenuItemData* pData = pItemList->Insert( nItemId, MENUITEM_STRING,
+ nItemBits, rStr, Image(), this, nPos );
+
+ // update native menu
+ if( ImplGetSalMenu() && pData->pSalMenuItem )
+ ImplGetSalMenu()->InsertItem( pData->pSalMenuItem, nPos );
+
+ Window* pWin = ImplGetWindow();
+ delete mpLayoutData, mpLayoutData = NULL;
+ if ( pWin )
+ {
+ ImplCalcSize( pWin );
+ if ( pWin->IsVisible() )
+ pWin->Invalidate();
+ }
+ ImplCallEventListeners( VCLEVENT_MENU_INSERTITEM, nPos );
+}
+
+void Menu::InsertItem( USHORT nItemId, const Image& rImage,
+ MenuItemBits nItemBits, USHORT nPos )
+{
+ InsertItem( nItemId, ImplGetSVEmptyStr(), nItemBits, nPos );
+ SetItemImage( nItemId, rImage );
+}
+
+void Menu::InsertItem( USHORT nItemId,
+ const XubString& rStr, const Image& rImage,
+ MenuItemBits nItemBits, USHORT nPos )
+{
+ InsertItem( nItemId, rStr, nItemBits, nPos );
+ SetItemImage( nItemId, rImage );
+}
+
+void Menu::InsertItem( const ResId& rResId, USHORT nPos )
+{
+ ResMgr* pMgr = rResId.GetResMgr();
+ if( ! pMgr )
+ return;
+
+ ULONG nObjMask;
+
+ GetRes( rResId.SetRT( RSC_MENUITEM ) );
+ nObjMask = ReadLongRes();
+
+ BOOL bSep = FALSE;
+ if ( nObjMask & RSC_MENUITEM_SEPARATOR )
+ bSep = (BOOL)ReadShortRes();
+
+ USHORT nItemId = 1;
+ if ( nObjMask & RSC_MENUITEM_ID )
+ nItemId = sal::static_int_cast<USHORT>(ReadLongRes());
+
+ MenuItemBits nStatus = 0;
+ if ( nObjMask & RSC_MENUITEM_STATUS )
+ nStatus = sal::static_int_cast<MenuItemBits>(ReadLongRes());
+
+ String aText;
+ if ( nObjMask & RSC_MENUITEM_TEXT )
+ aText = ReadStringRes();
+
+ // Item erzeugen
+ if ( nObjMask & RSC_MENUITEM_BITMAP )
+ {
+ if ( !bSep )
+ {
+ Bitmap aBmp( ResId( (RSHEADER_TYPE*)GetClassRes(), *pMgr ) );
+ if ( aText.Len() )
+ InsertItem( nItemId, aText, aBmp, nStatus, nPos );
+ else
+ InsertItem( nItemId, aBmp, nStatus, nPos );
+ }
+ IncrementRes( GetObjSizeRes( (RSHEADER_TYPE*)GetClassRes() ) );
+ }
+ else if ( !bSep )
+ InsertItem( nItemId, aText, nStatus, nPos );
+ if ( bSep )
+ InsertSeparator( nPos );
+
+ String aHelpText;
+ if ( nObjMask & RSC_MENUITEM_HELPTEXT )
+ {
+ aHelpText = ReadStringRes();
+ if( !bSep )
+ SetHelpText( nItemId, aHelpText );
+ }
+
+ ULONG nHelpId = 0;
+ if ( nObjMask & RSC_MENUITEM_HELPID )
+ {
+ nHelpId = ReadLongRes();
+ if ( !bSep )
+ SetHelpId( nItemId, nHelpId );
+ }
+
+ if( !bSep /* && SvHelpSettings::HelpText( aHelpText, nHelpId ) */ )
+ SetHelpText( nItemId, aHelpText );
+
+ if ( nObjMask & RSC_MENUITEM_KEYCODE )
+ {
+ if ( !bSep )
+ SetAccelKey( nItemId, KeyCode( ResId( (RSHEADER_TYPE*)GetClassRes(), *pMgr ) ) );
+ IncrementRes( GetObjSizeRes( (RSHEADER_TYPE*)GetClassRes() ) );
+ }
+ if( nObjMask & RSC_MENUITEM_CHECKED )
+ {
+ if ( !bSep )
+ CheckItem( nItemId, (BOOL)ReadShortRes() );
+ }
+ if ( nObjMask & RSC_MENUITEM_DISABLE )
+ {
+ if ( !bSep )
+ EnableItem( nItemId, !(BOOL)ReadShortRes() );
+ }
+ if ( nObjMask & RSC_MENUITEM_COMMAND )
+ {
+ String aCommandStr = ReadStringRes();
+ if ( !bSep )
+ SetItemCommand( nItemId, aCommandStr );
+ }
+ if ( nObjMask & RSC_MENUITEM_MENU )
+ {
+ if ( !bSep )
+ {
+ MenuItemData* pData = GetItemList()->GetData( nItemId );
+ if ( pData )
+ {
+ PopupMenu* pSubMenu = new PopupMenu( ResId( (RSHEADER_TYPE*)GetClassRes(), *pMgr ) );
+ pData->pAutoSubMenu = pSubMenu;
+ // #111060# keep track of this pointer, may be it will be deleted from outside
+ pSubMenu->pRefAutoSubMenu = &pData->pAutoSubMenu;
+ SetPopupMenu( nItemId, pSubMenu );
+ }
+ }
+ IncrementRes( GetObjSizeRes( (RSHEADER_TYPE*)GetClassRes() ) );
+ }
+ delete mpLayoutData, mpLayoutData = NULL;
+}
+
+void Menu::InsertSeparator( USHORT nPos )
+{
+ // do nothing if its a menu bar
+ if ( bIsMenuBar )
+ return;
+
+ // if position > ItemCount, append
+ if ( nPos >= (USHORT)pItemList->Count() )
+ nPos = MENU_APPEND;
+
+ // put separator in item list
+ pItemList->InsertSeparator( nPos );
+
+ // update native menu
+ USHORT itemPos = nPos != MENU_APPEND ? nPos : (USHORT)pItemList->Count() - 1;
+ MenuItemData *pData = pItemList->GetDataFromPos( itemPos );
+ if( ImplGetSalMenu() && pData && pData->pSalMenuItem )
+ ImplGetSalMenu()->InsertItem( pData->pSalMenuItem, nPos );
+
+ delete mpLayoutData, mpLayoutData = NULL;
+
+ ImplCallEventListeners( VCLEVENT_MENU_INSERTITEM, nPos );
+}
+
+void Menu::RemoveItem( USHORT nPos )
+{
+ BOOL bRemove = FALSE;
+
+ if ( nPos < GetItemCount() )
+ {
+ // update native menu
+ if( ImplGetSalMenu() )
+ ImplGetSalMenu()->RemoveItem( nPos );
+
+ pItemList->Remove( nPos );
+ bRemove = TRUE;
+ }
+
+ Window* pWin = ImplGetWindow();
+ if ( pWin )
+ {
+ ImplCalcSize( pWin );
+ if ( pWin->IsVisible() )
+ pWin->Invalidate();
+ }
+ delete mpLayoutData, mpLayoutData = NULL;
+
+ if ( bRemove )
+ ImplCallEventListeners( VCLEVENT_MENU_REMOVEITEM, nPos );
+}
+
+void ImplCopyItem( Menu* pThis, const Menu& rMenu, USHORT nPos, USHORT nNewPos,
+ USHORT nMode = 0 )
+{
+ MenuItemType eType = rMenu.GetItemType( nPos );
+
+ if ( eType == MENUITEM_DONTKNOW )
+ return;
+
+ if ( eType == MENUITEM_SEPARATOR )
+ pThis->InsertSeparator( nNewPos );
+ else
+ {
+ USHORT nId = rMenu.GetItemId( nPos );
+
+ DBG_ASSERT( pThis->GetItemPos( nId ) == MENU_ITEM_NOTFOUND,
+ "Menu::CopyItem(): ItemId already exists" );
+
+ MenuItemData* pData = rMenu.GetItemList()->GetData( nId );
+
+ if ( eType == MENUITEM_STRINGIMAGE )
+ pThis->InsertItem( nId, pData->aText, pData->aImage, pData->nBits, nNewPos );
+ else if ( eType == MENUITEM_STRING )
+ pThis->InsertItem( nId, pData->aText, pData->nBits, nNewPos );
+ else
+ pThis->InsertItem( nId, pData->aImage, pData->nBits, nNewPos );
+
+ if ( rMenu.IsItemChecked( nId ) )
+ pThis->CheckItem( nId, TRUE );
+ if ( !rMenu.IsItemEnabled( nId ) )
+ pThis->EnableItem( nId, FALSE );
+ pThis->SetHelpId( nId, pData->nHelpId );
+ pThis->SetHelpText( nId, pData->aHelpText );
+ pThis->SetAccelKey( nId, pData->aAccelKey );
+ pThis->SetItemCommand( nId, pData->aCommandStr );
+ pThis->SetHelpCommand( nId, pData->aHelpCommandStr );
+
+ PopupMenu* pSubMenu = rMenu.GetPopupMenu( nId );
+ if ( pSubMenu )
+ {
+ // AutoKopie anlegen
+ if ( nMode == 1 )
+ {
+ PopupMenu* pNewMenu = new PopupMenu( *pSubMenu );
+ pThis->SetPopupMenu( nId, pNewMenu );
+// SetAutoMenu( pThis, nId, pNewMenu );
+ }
+ else
+ pThis->SetPopupMenu( nId, pSubMenu );
+ }
+ }
+}
+
+void Menu::CopyItem( const Menu& rMenu, USHORT nPos, USHORT nNewPos )
+{
+ ImplCopyItem( this, rMenu, nPos, nNewPos );
+}
+
+void Menu::Clear()
+{
+ for ( USHORT i = GetItemCount(); i; i-- )
+ RemoveItem( 0 );
+}
+
+USHORT Menu::GetItemCount() const
+{
+ return (USHORT)pItemList->Count();
+}
+
+USHORT Menu::ImplGetVisibleItemCount() const
+{
+ USHORT nItems = 0;
+ for ( USHORT n = (USHORT)pItemList->Count(); n; )
+ {
+ if ( ImplIsVisible( --n ) )
+ nItems++;
+ }
+ return nItems;
+}
+
+USHORT Menu::ImplGetFirstVisible() const
+{
+ for ( USHORT n = 0; n < pItemList->Count(); n++ )
+ {
+ if ( ImplIsVisible( n ) )
+ return n;
+ }
+ return ITEMPOS_INVALID;
+}
+
+USHORT Menu::ImplGetPrevVisible( USHORT nPos ) const
+{
+ for ( USHORT n = nPos; n; )
+ {
+ if ( n && ImplIsVisible( --n ) )
+ return n;
+ }
+ return ITEMPOS_INVALID;
+}
+
+USHORT Menu::ImplGetNextVisible( USHORT nPos ) const
+{
+ for ( USHORT n = nPos+1; n < pItemList->Count(); n++ )
+ {
+ if ( ImplIsVisible( n ) )
+ return n;
+ }
+ return ITEMPOS_INVALID;
+}
+
+USHORT Menu::GetItemId( USHORT nPos ) const
+{
+ MenuItemData* pData = pItemList->GetDataFromPos( nPos );
+
+ if ( pData )
+ return pData->nId;
+ else
+ return 0;
+}
+
+USHORT Menu::GetItemPos( USHORT nItemId ) const
+{
+ USHORT nPos;
+ MenuItemData* pData = pItemList->GetData( nItemId, nPos );
+
+ if ( pData )
+ return nPos;
+ else
+ return MENU_ITEM_NOTFOUND;
+}
+
+MenuItemType Menu::GetItemType( USHORT nPos ) const
+{
+ MenuItemData* pData = pItemList->GetDataFromPos( nPos );
+
+ if ( pData )
+ return pData->eType;
+ else
+ return MENUITEM_DONTKNOW;
+}
+
+USHORT Menu::GetCurItemId() const
+{
+ return nSelectedId;
+}
+
+void Menu::SetItemBits( USHORT nItemId, MenuItemBits nBits )
+{
+ MenuItemData* pData = pItemList->GetData( nItemId );
+ if ( pData )
+ pData->nBits = nBits;
+}
+
+MenuItemBits Menu::GetItemBits( USHORT nItemId ) const
+{
+ MenuItemBits nBits = 0;
+ MenuItemData* pData = pItemList->GetData( nItemId );
+ if ( pData )
+ nBits = pData->nBits;
+ return nBits;
+}
+
+void Menu::SetUserValue( USHORT nItemId, ULONG nValue )
+{
+ MenuItemData* pData = pItemList->GetData( nItemId );
+ if ( pData )
+ pData->nUserValue = nValue;
+}
+
+ULONG Menu::GetUserValue( USHORT nItemId ) const
+{
+ MenuItemData* pData = pItemList->GetData( nItemId );
+ return pData ? pData->nUserValue : 0;
+}
+
+void Menu::SetPopupMenu( USHORT nItemId, PopupMenu* pMenu )
+{
+ USHORT nPos;
+ MenuItemData* pData = pItemList->GetData( nItemId, nPos );
+
+ // Item does not exist -> return NULL
+ if ( !pData )
+ return;
+
+ // same menu, nothing to do
+ if ( (PopupMenu*)pData->pSubMenu == pMenu )
+ return;
+
+ // data exchange
+ pData->pSubMenu = pMenu;
+
+ // #112023# Make sure pStartedFrom does not point to invalid (old) data
+ if ( pData->pSubMenu )
+ pData->pSubMenu->pStartedFrom = 0;
+
+ // set native submenu
+ if( ImplGetSalMenu() && pData->pSalMenuItem )
+ {
+ if( pMenu )
+ ImplGetSalMenu()->SetSubMenu( pData->pSalMenuItem, pMenu->ImplGetSalMenu(), nPos );
+ else
+ ImplGetSalMenu()->SetSubMenu( pData->pSalMenuItem, NULL, nPos );
+ }
+
+ ImplCallEventListeners( VCLEVENT_MENU_SUBMENUCHANGED, nPos );
+}
+
+PopupMenu* Menu::GetPopupMenu( USHORT nItemId ) const
+{
+ MenuItemData* pData = pItemList->GetData( nItemId );
+
+ if ( pData )
+ return (PopupMenu*)(pData->pSubMenu);
+ else
+ return NULL;
+}
+
+void Menu::SetAccelKey( USHORT nItemId, const KeyCode& rKeyCode )
+{
+ USHORT nPos;
+ MenuItemData* pData = pItemList->GetData( nItemId, nPos );
+
+ if ( !pData )
+ return;
+
+ if ( pData->aAccelKey == rKeyCode )
+ return;
+
+ pData->aAccelKey = rKeyCode;
+
+ // update native menu
+ if( ImplGetSalMenu() && pData->pSalMenuItem )
+ ImplGetSalMenu()->SetAccelerator( nPos, pData->pSalMenuItem, rKeyCode, rKeyCode.GetName() );
+}
+
+KeyCode Menu::GetAccelKey( USHORT nItemId ) const
+{
+ MenuItemData* pData = pItemList->GetData( nItemId );
+
+ if ( pData )
+ return pData->aAccelKey;
+ else
+ return KeyCode();
+}
+
+KeyEvent Menu::GetActivationKey( USHORT nItemId ) const
+{
+ KeyEvent aRet;
+ MenuItemData* pData = pItemList->GetData( nItemId );
+ if( pData )
+ {
+ USHORT nPos = pData->aText.Search( '~' );
+ if( nPos != STRING_NOTFOUND && nPos < pData->aText.Len()-1 )
+ {
+ USHORT nCode = 0;
+ sal_Unicode cAccel = pData->aText.GetChar( nPos+1 );
+ if( cAccel >= 'a' && cAccel <= 'z' )
+ nCode = KEY_A + (cAccel-'a');
+ else if( cAccel >= 'A' && cAccel <= 'Z' )
+ nCode = KEY_A + (cAccel-'A');
+ else if( cAccel >= '0' && cAccel <= '9' )
+ nCode = KEY_0 + (cAccel-'0');
+ if(nCode )
+ aRet = KeyEvent( cAccel, KeyCode( nCode, KEY_MOD2 ) );
+ }
+
+ }
+ return aRet;
+}
+
+void Menu::CheckItem( USHORT nItemId, BOOL bCheck )
+{
+ USHORT nPos;
+ MenuItemData* pData = pItemList->GetData( nItemId, nPos );
+
+ if ( !pData || pData->bChecked == bCheck )
+ return;
+
+ // Wenn RadioCheck, dann vorherigen unchecken
+ if ( bCheck && (pData->nBits & MIB_AUTOCHECK) &&
+ (pData->nBits & MIB_RADIOCHECK) )
+ {
+ MenuItemData* pGroupData;
+ USHORT nGroupPos;
+ USHORT nItemCount = GetItemCount();
+ BOOL bFound = FALSE;
+
+ nGroupPos = nPos;
+ while ( nGroupPos )
+ {
+ pGroupData = pItemList->GetDataFromPos( nGroupPos-1 );
+ if ( pGroupData->nBits & MIB_RADIOCHECK )
+ {
+ if ( IsItemChecked( pGroupData->nId ) )
+ {
+ CheckItem( pGroupData->nId, FALSE );
+ bFound = TRUE;
+ break;
+ }
+ }
+ else
+ break;
+ nGroupPos--;
+ }
+
+ if ( !bFound )
+ {
+ nGroupPos = nPos+1;
+ while ( nGroupPos < nItemCount )
+ {
+ pGroupData = pItemList->GetDataFromPos( nGroupPos );
+ if ( pGroupData->nBits & MIB_RADIOCHECK )
+ {
+ if ( IsItemChecked( pGroupData->nId ) )
+ {
+ CheckItem( pGroupData->nId, FALSE );
+ break;
+ }
+ }
+ else
+ break;
+ nGroupPos++;
+ }
+ }
+ }
+
+ pData->bChecked = bCheck;
+
+ // update native menu
+ if( ImplGetSalMenu() )
+ ImplGetSalMenu()->CheckItem( nPos, bCheck );
+
+ ImplCallEventListeners( bCheck ? VCLEVENT_MENU_ITEMCHECKED : VCLEVENT_MENU_ITEMUNCHECKED, nPos );
+}
+
+BOOL Menu::IsItemChecked( USHORT nItemId ) const
+{
+ USHORT nPos;
+ MenuItemData* pData = pItemList->GetData( nItemId, nPos );
+
+ if ( !pData )
+ return FALSE;
+
+ return pData->bChecked;
+}
+
+void Menu::EnableItem( USHORT nItemId, BOOL bEnable )
+{
+ USHORT nPos;
+ MenuItemData* pItemData = pItemList->GetData( nItemId, nPos );
+
+ if ( pItemData && ( pItemData->bEnabled != bEnable ) )
+ {
+ pItemData->bEnabled = bEnable;
+
+ Window* pWin = ImplGetWindow();
+ if ( pWin && pWin->IsVisible() )
+ {
+ DBG_ASSERT( bIsMenuBar, "Menu::EnableItem - Popup visible!" );
+ long nX = 0;
+ ULONG nCount = pItemList->Count();
+ for ( ULONG n = 0; n < nCount; n++ )
+ {
+ MenuItemData* pData = pItemList->GetDataFromPos( n );
+ if ( n == nPos )
+ {
+ pWin->Invalidate( Rectangle( Point( nX, 0 ), Size( pData->aSz.Width(), pData->aSz.Height() ) ) );
+ break;
+ }
+ nX += pData->aSz.Width();
+ }
+ }
+ // update native menu
+ if( ImplGetSalMenu() )
+ ImplGetSalMenu()->EnableItem( nPos, bEnable );
+
+ ImplCallEventListeners( bEnable ? VCLEVENT_MENU_ENABLE : VCLEVENT_MENU_DISABLE, nPos );
+ }
+}
+
+BOOL Menu::IsItemEnabled( USHORT nItemId ) const
+{
+ USHORT nPos;
+ MenuItemData* pData = pItemList->GetData( nItemId, nPos );
+
+ if ( !pData )
+ return FALSE;
+
+ return pData->bEnabled;
+}
+
+void Menu::ShowItem( USHORT nItemId, BOOL bVisible )
+{
+ USHORT nPos;
+ MenuItemData* pData = pItemList->GetData( nItemId, nPos );
+
+ DBG_ASSERT( !bIsMenuBar, "Menu::ShowItem - ignored for menu bar entries!" );
+ if ( !bIsMenuBar && pData && ( pData->bVisible != bVisible ) )
+ {
+ Window* pWin = ImplGetWindow();
+ if ( pWin && pWin->IsVisible() )
+ {
+ DBG_ASSERT( 0, "Menu::ShowItem - ignored for visible popups!" );
+ return;
+ }
+ pData->bVisible = bVisible;
+
+ // update native menu
+ // as long as there is no support to hide native menu entries, we just disable them
+ // TODO: add support to show/hide native menu entries
+ if( ImplGetSalMenu() )
+ ImplGetSalMenu()->EnableItem( nPos, bVisible );
+ }
+}
+
+void Menu::SetItemText( USHORT nItemId, const XubString& rStr )
+{
+ USHORT nPos;
+ MenuItemData* pData = pItemList->GetData( nItemId, nPos );
+
+ if ( !pData )
+ return;
+
+ if ( !rStr.Equals( pData->aText ) )
+ {
+ pData->aText = rStr;
+ ImplSetMenuItemData( pData );
+ // update native menu
+ if( ImplGetSalMenu() && pData->pSalMenuItem )
+ ImplGetSalMenu()->SetItemText( nPos, pData->pSalMenuItem, rStr );
+
+ Window* pWin = ImplGetWindow();
+ delete mpLayoutData, mpLayoutData = NULL;
+ if ( pWin && IsMenuBar() )
+ {
+ ImplCalcSize( pWin );
+ if ( pWin->IsVisible() )
+ pWin->Invalidate();
+ }
+
+ ImplCallEventListeners( VCLEVENT_MENU_ITEMTEXTCHANGED, nPos );
+ }
+}
+
+XubString Menu::GetItemText( USHORT nItemId ) const
+{
+ USHORT nPos;
+ MenuItemData* pData = pItemList->GetData( nItemId, nPos );
+
+ if ( pData )
+ return pData->aText;
+ else
+ return ImplGetSVEmptyStr();
+}
+
+void Menu::SetItemImage( USHORT nItemId, const Image& rImage )
+{
+ USHORT nPos;
+ MenuItemData* pData = pItemList->GetData( nItemId, nPos );
+
+ if ( !pData )
+ return;
+
+ pData->aImage = rImage;
+ ImplSetMenuItemData( pData );
+
+ // update native menu
+ if( ImplGetSalMenu() && pData->pSalMenuItem )
+ ImplGetSalMenu()->SetItemImage( nPos, pData->pSalMenuItem, rImage );
+}
+
+static inline Image ImplRotImage( const Image& rImage, long nAngle10 )
+{
+ Image aRet;
+ BitmapEx aBmpEx( rImage.GetBitmapEx() );
+
+ aBmpEx.Rotate( nAngle10, COL_WHITE );
+
+ return Image( aBmpEx );
+}
+
+void Menu::SetItemImageAngle( USHORT nItemId, long nAngle10 )
+{
+ USHORT nPos;
+ MenuItemData* pData = pItemList->GetData( nItemId, nPos );
+
+ if ( pData )
+ {
+ long nDeltaAngle = (nAngle10 - pData->nItemImageAngle) % 3600;
+ while( nDeltaAngle < 0 )
+ nDeltaAngle += 3600;
+
+ pData->nItemImageAngle = nAngle10;
+ if( nDeltaAngle && !!pData->aImage )
+ pData->aImage = ImplRotImage( pData->aImage, nDeltaAngle );
+ }
+}
+
+static inline Image ImplMirrorImage( const Image& rImage )
+{
+ Image aRet;
+ BitmapEx aBmpEx( rImage.GetBitmapEx() );
+
+ aBmpEx.Mirror( BMP_MIRROR_HORZ );
+
+ return Image( aBmpEx );
+}
+
+void Menu::SetItemImageMirrorMode( USHORT nItemId, BOOL bMirror )
+{
+ USHORT nPos;
+ MenuItemData* pData = pItemList->GetData( nItemId, nPos );
+
+ if ( pData )
+ {
+ if( ( pData->bMirrorMode && ! bMirror ) ||
+ ( ! pData->bMirrorMode && bMirror )
+ )
+ {
+ pData->bMirrorMode = bMirror ? true : false;
+ if( !!pData->aImage )
+ pData->aImage = ImplMirrorImage( pData->aImage );
+ }
+ }
+}
+
+Image Menu::GetItemImage( USHORT nItemId ) const
+{
+ MenuItemData* pData = pItemList->GetData( nItemId );
+
+ if ( pData )
+ return pData->aImage;
+ else
+ return Image();
+}
+
+long Menu::GetItemImageAngle( USHORT nItemId ) const
+{
+ MenuItemData* pData = pItemList->GetData( nItemId );
+
+ if ( pData )
+ return pData->nItemImageAngle;
+ else
+ return 0;
+}
+
+BOOL Menu::GetItemImageMirrorMode( USHORT nItemId ) const
+{
+ MenuItemData* pData = pItemList->GetData( nItemId );
+
+ if ( pData )
+ return pData->bMirrorMode;
+ else
+ return FALSE;
+}
+
+void Menu::SetItemCommand( USHORT nItemId, const String& rCommand )
+{
+ MenuItemData* pData = pItemList->GetData( nItemId );
+
+ if ( pData )
+ pData->aCommandStr = rCommand;
+}
+
+const XubString& Menu::GetItemCommand( USHORT nItemId ) const
+{
+ MenuItemData* pData = pItemList->GetData( nItemId );
+
+ if ( pData )
+ return pData->aCommandStr;
+ else
+ return ImplGetSVEmptyStr();
+}
+
+void Menu::SetHelpCommand( USHORT nItemId, const XubString& rStr )
+{
+ MenuItemData* pData = pItemList->GetData( nItemId );
+
+ if ( pData )
+ pData->aHelpCommandStr = rStr;
+}
+
+const XubString& Menu::GetHelpCommand( USHORT nItemId ) const
+{
+ MenuItemData* pData = pItemList->GetData( nItemId );
+
+ if ( pData )
+ return pData->aHelpCommandStr;
+ else
+ return ImplGetSVEmptyStr();
+}
+
+void Menu::SetHelpText( USHORT nItemId, const XubString& rStr )
+{
+ MenuItemData* pData = pItemList->GetData( nItemId );
+
+ if ( pData )
+ pData->aHelpText = rStr;
+}
+
+const XubString& Menu::ImplGetHelpText( USHORT nItemId ) const
+{
+ MenuItemData* pData = pItemList->GetData( nItemId );
+
+ if ( pData )
+ {
+ if ( !pData->aHelpText.Len() &&
+ (( pData->nHelpId ) || ( pData->aCommandStr.Len() )))
+ {
+ Help* pHelp = Application::GetHelp();
+ if ( pHelp )
+ {
+ if ( pData->aCommandStr.Len() )
+ pData->aHelpText = pHelp->GetHelpText( pData->aCommandStr, NULL );
+
+ if( !pData->aHelpText.Len() && pData->nHelpId )
+ pData->aHelpText = pHelp->GetHelpText( pData->nHelpId, NULL );
+ }
+ }
+
+ return pData->aHelpText;
+ }
+ else
+ return ImplGetSVEmptyStr();
+}
+
+const XubString& Menu::GetHelpText( USHORT nItemId ) const
+{
+ return ImplGetHelpText( nItemId );
+}
+
+void Menu::SetTipHelpText( USHORT nItemId, const XubString& rStr )
+{
+ MenuItemData* pData = pItemList->GetData( nItemId );
+
+ if ( pData )
+ pData->aTipHelpText = rStr;
+}
+
+const XubString& Menu::GetTipHelpText( USHORT nItemId ) const
+{
+ MenuItemData* pData = pItemList->GetData( nItemId );
+
+ if ( pData )
+ return pData->aTipHelpText;
+ else
+ return ImplGetSVEmptyStr();
+}
+
+void Menu::SetHelpId( USHORT nItemId, ULONG nHelpId )
+{
+ MenuItemData* pData = pItemList->GetData( nItemId );
+
+ if ( pData )
+ pData->nHelpId = nHelpId;
+}
+
+ULONG Menu::GetHelpId( USHORT nItemId ) const
+{
+ MenuItemData* pData = pItemList->GetData( nItemId );
+
+ if ( pData )
+ return pData->nHelpId;
+ else
+ return 0;
+}
+
+Menu& Menu::operator=( const Menu& rMenu )
+{
+ // Aufraeumen
+ Clear();
+
+ // Items kopieren
+ USHORT nCount = rMenu.GetItemCount();
+ for ( USHORT i = 0; i < nCount; i++ )
+ ImplCopyItem( this, rMenu, i, MENU_APPEND, 1 );
+
+ nDefaultItem = rMenu.nDefaultItem;
+ aActivateHdl = rMenu.aActivateHdl;
+ aDeactivateHdl = rMenu.aDeactivateHdl;
+ aHighlightHdl = rMenu.aHighlightHdl;
+ aSelectHdl = rMenu.aSelectHdl;
+ aTitleText = rMenu.aTitleText;
+ bIsMenuBar = rMenu.bIsMenuBar;
+
+ return *this;
+}
+
+BOOL Menu::ImplIsVisible( USHORT nPos ) const
+{
+ BOOL bVisible = TRUE;
+
+ MenuItemData* pData = pItemList->GetDataFromPos( nPos );
+ // check general visibility first
+ if( pData && !pData->bVisible )
+ bVisible = FALSE;
+
+ if ( bVisible && pData && pData->eType == MENUITEM_SEPARATOR )
+ {
+ if( nPos == 0 ) // no separator should be shown at the very beginning
+ bVisible = FALSE;
+ else
+ {
+ // always avoid adjacent separators
+ USHORT nCount = (USHORT) pItemList->Count();
+ USHORT n;
+ MenuItemData* pNextData = NULL;
+ // search next visible item
+ for( n = nPos + 1; n < nCount; n++ )
+ {
+ pNextData = pItemList->GetDataFromPos( n );
+ if( pNextData && pNextData->bVisible )
+ {
+ if( pNextData->eType == MENUITEM_SEPARATOR || ImplIsVisible(n) )
+ break;
+ }
+ }
+ if( n == nCount ) // no next visible item
+ bVisible = FALSE;
+ // check for separator
+ if( pNextData && pNextData->bVisible && pNextData->eType == MENUITEM_SEPARATOR )
+ bVisible = FALSE;
+
+ if( bVisible )
+ {
+ for( n = nPos; n > 0; n-- )
+ {
+ pNextData = pItemList->GetDataFromPos( n-1 );
+ if( pNextData && pNextData->bVisible )
+ {
+ if( pNextData->eType != MENUITEM_SEPARATOR && ImplIsVisible(n-1) )
+ break;
+ }
+ }
+ if( n == 0 ) // no previous visible item
+ bVisible = FALSE;
+ }
+ }
+ }
+
+ // Fuer den Menubar nicht erlaubt, weil ich nicht mitbekomme
+ // ob dadurch ein Eintrag verschwindet oder wieder da ist.
+ if ( bVisible && !bIsMenuBar && ( nMenuFlags & MENU_FLAG_HIDEDISABLEDENTRIES ) &&
+ !( nMenuFlags & MENU_FLAG_ALWAYSSHOWDISABLEDENTRIES ) )
+ {
+ if( !pData ) // e.g. nPos == ITEMPOS_INVALID
+ bVisible = FALSE;
+ else if ( pData->eType != MENUITEM_SEPARATOR ) // separators handled above
+ {
+ // bVisible = pData->bEnabled && ( !pData->pSubMenu || pData->pSubMenu->HasValidEntries( TRUE ) );
+ bVisible = pData->bEnabled; // SubMenus nicht pruefen, weil sie ggf. erst im Activate() gefuellt werden.
+ }
+ }
+
+ return bVisible;
+}
+
+BOOL Menu::IsItemVisible( USHORT nItemId ) const
+{
+ return IsMenuVisible() && ImplIsVisible( GetItemPos( nItemId ) );
+}
+
+BOOL Menu::IsItemPosVisible( USHORT nItemPos ) const
+{
+ return IsMenuVisible() && ImplIsVisible( nItemPos );
+}
+
+BOOL Menu::IsMenuVisible() const
+{
+ return pWindow && pWindow->IsReallyVisible();
+}
+
+BOOL Menu::ImplIsSelectable( USHORT nPos ) const
+{
+ BOOL bSelectable = TRUE;
+
+ MenuItemData* pData = pItemList->GetDataFromPos( nPos );
+ // check general visibility first
+ if ( pData && ( pData->nBits & MIB_NOSELECT ) )
+ bSelectable = FALSE;
+
+ return bSelectable;
+}
+
+void Menu::SelectItem( USHORT nItemId )
+{
+ if( bIsMenuBar )
+ static_cast<MenuBar*>(this)->SelectEntry( nItemId );
+ else
+ static_cast<PopupMenu*>(this)->SelectEntry( nItemId );
+}
+
+::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible > Menu::GetAccessible()
+{
+ // Since PopupMenu are sometimes shared by different instances of MenuBar, the mxAccessible member gets
+ // overwritten and may contain a disposed object when the initial menubar gets set again. So use the
+ // mxAccessible member only for sub menus.
+ if ( pStartedFrom )
+ {
+ for ( sal_uInt16 i = 0, nCount = pStartedFrom->GetItemCount(); i < nCount; ++i )
+ {
+ sal_uInt16 nItemId = pStartedFrom->GetItemId( i );
+ if ( static_cast< Menu* >( pStartedFrom->GetPopupMenu( nItemId ) ) == this )
+ {
+ ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible > xParent = pStartedFrom->GetAccessible();
+ if ( xParent.is() )
+ {
+ ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessibleContext > xParentContext( xParent->getAccessibleContext() );
+ if ( xParentContext.is() )
+ return xParentContext->getAccessibleChild( i );
+ }
+ }
+ }
+ }
+ else if ( !mxAccessible.is() )
+ {
+ UnoWrapperBase* pWrapper = Application::GetUnoWrapper();
+ if ( pWrapper )
+ mxAccessible = pWrapper->CreateAccessible( this, bIsMenuBar );
+ }
+
+ return mxAccessible;
+}
+
+void Menu::SetAccessible( const ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible >& rxAccessible )
+{
+ mxAccessible = rxAccessible;
+}
+
+long Menu::ImplGetNativeCheckAndRadioSize( Window* pWin, long& rCheckHeight, long& rRadioHeight, long &rMaxWidth ) const
+{
+ rMaxWidth = rCheckHeight = rRadioHeight = 0;
+
+ if( ! bIsMenuBar )
+ {
+ ImplControlValue aVal;
+ Rectangle aNativeBounds;
+ Rectangle aNativeContent;
+ Point tmp( 0, 0 );
+ Rectangle aCtrlRegion( Rectangle( tmp, Size( 100, 15 ) ) );
+ if( pWin->IsNativeControlSupported( CTRL_MENU_POPUP, PART_MENU_ITEM_CHECK_MARK ) )
+ {
+ if( pWin->GetNativeControlRegion( ControlType(CTRL_MENU_POPUP),
+ ControlPart(PART_MENU_ITEM_CHECK_MARK),
+ aCtrlRegion,
+ ControlState(CTRL_STATE_ENABLED),
+ aVal,
+ OUString(),
+ aNativeBounds,
+ aNativeContent )
+ )
+ {
+ rCheckHeight = aNativeBounds.GetHeight();
+ rMaxWidth = aNativeContent.GetWidth();
+ }
+ }
+ if( pWin->IsNativeControlSupported( CTRL_MENU_POPUP, PART_MENU_ITEM_RADIO_MARK ) )
+ {
+ if( pWin->GetNativeControlRegion( ControlType(CTRL_MENU_POPUP),
+ ControlPart(PART_MENU_ITEM_RADIO_MARK),
+ aCtrlRegion,
+ ControlState(CTRL_STATE_ENABLED),
+ aVal,
+ OUString(),
+ aNativeBounds,
+ aNativeContent )
+ )
+ {
+ rRadioHeight = aNativeBounds.GetHeight();
+ rMaxWidth = Max (rMaxWidth, aNativeContent.GetWidth());
+ }
+ }
+ }
+ return (rCheckHeight > rRadioHeight) ? rCheckHeight : rRadioHeight;
+}
+
+// -----------------------------------------------------------------------
+
+void Menu::ImplAddDel( ImplMenuDelData& rDel )
+{
+ DBG_ASSERT( !rDel.mpMenu, "Menu::ImplAddDel(): cannot add ImplMenuDelData twice !" );
+ if( !rDel.mpMenu )
+ {
+ rDel.mpMenu = this;
+ rDel.mpNext = mpFirstDel;
+ mpFirstDel = &rDel;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Menu::ImplRemoveDel( ImplMenuDelData& rDel )
+{
+ rDel.mpMenu = NULL;
+ if ( mpFirstDel == &rDel )
+ {
+ mpFirstDel = rDel.mpNext;
+ }
+ else
+ {
+ ImplMenuDelData* pData = mpFirstDel;
+ while ( pData && (pData->mpNext != &rDel) )
+ pData = pData->mpNext;
+
+ DBG_ASSERT( pData, "Menu::ImplRemoveDel(): ImplMenuDelData not registered !" );
+ if( pData )
+ pData->mpNext = rDel.mpNext;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+Size Menu::ImplCalcSize( Window* pWin )
+{
+ // | Checked| Image| Text| Accel/Popup|
+
+ // Fuer Symbole: nFontHeight x nFontHeight
+ long nFontHeight = pWin->GetTextHeight();
+ long nExtra = nFontHeight/4;
+
+
+ Size aSz;
+ Size aMaxImgSz;
+ long nMaxWidth = 0;
+ long nMinMenuItemHeight = nFontHeight;
+ long nCheckHeight = 0, nRadioHeight = 0;
+ long nCheckWidth = 0, nMaxCheckWidth = 0;
+ long nMax = ImplGetNativeCheckAndRadioSize( pWin, nCheckHeight, nRadioHeight, nMaxCheckWidth );
+ if( nMax > nMinMenuItemHeight )
+ nMinMenuItemHeight = nMax;
+
+ const StyleSettings& rSettings = pWin->GetSettings().GetStyleSettings();
+ if ( rSettings.GetUseImagesInMenus() )
+ {
+ nMinMenuItemHeight = 16;
+ for ( USHORT i = (USHORT)pItemList->Count(); i; )
+ {
+ MenuItemData* pData = pItemList->GetDataFromPos( --i );
+ if ( ImplIsVisible( i ) && (( pData->eType == MENUITEM_IMAGE ) || ( pData->eType == MENUITEM_STRINGIMAGE )))
+ {
+ Size aImgSz = pData->aImage.GetSizePixel();
+ if ( aImgSz.Height() > aMaxImgSz.Height() )
+ aMaxImgSz.Height() = aImgSz.Height();
+ if ( aImgSz.Height() > nMinMenuItemHeight )
+ nMinMenuItemHeight = aImgSz.Height();
+ break;
+ }
+ }
+ }
+
+ for ( USHORT n = (USHORT)pItemList->Count(); n; )
+ {
+ MenuItemData* pData = pItemList->GetDataFromPos( --n );
+
+ pData->aSz.Height() = 0;
+ pData->aSz.Width() = 0;
+
+ if ( ImplIsVisible( n ) )
+ {
+ long nWidth = 0;
+
+ // Separator
+ if ( !bIsMenuBar && ( pData->eType == MENUITEM_SEPARATOR ) )
+ {
+ DBG_ASSERT( !bIsMenuBar, "Separator in MenuBar ?! " );
+ pData->aSz.Height() = 4;
+ }
+
+ // Image:
+ if ( !bIsMenuBar && ( ( pData->eType == MENUITEM_IMAGE ) || ( pData->eType == MENUITEM_STRINGIMAGE ) ) )
+ {
+ Size aImgSz = pData->aImage.GetSizePixel();
+ aImgSz.Height() += 4; // add a border for native marks
+ aImgSz.Width() += 4; // add a border for native marks
+ if ( aImgSz.Width() > aMaxImgSz.Width() )
+ aMaxImgSz.Width() = aImgSz.Width();
+ if ( aImgSz.Height() > aMaxImgSz.Height() )
+ aMaxImgSz.Height() = aImgSz.Height();
+ if ( aImgSz.Height() > pData->aSz.Height() )
+ pData->aSz.Height() = aImgSz.Height();
+ }
+
+ // Check Buttons:
+ if ( !bIsMenuBar && pData->HasCheck() )
+ {
+ nCheckWidth = nMaxCheckWidth;
+ if (nMenuFlags & MENU_FLAG_SHOWCHECKIMAGES)
+ {
+ // checks / images take the same place
+ if( ! ( ( pData->eType == MENUITEM_IMAGE ) || ( pData->eType == MENUITEM_STRINGIMAGE ) ) )
+ nWidth += nCheckWidth + nExtra * 2;
+ }
+ }
+
+ // Text:
+ if ( (pData->eType == MENUITEM_STRING) || (pData->eType == MENUITEM_STRINGIMAGE) )
+ {
+ long nTextWidth = pWin->GetCtrlTextWidth( pData->aText );
+ long nTextHeight = pWin->GetTextHeight();
+
+// if ( nTextHeight > pData->aSz.Height() )
+// pData->aSz.Height() = nTextHeight;
+
+ if ( bIsMenuBar )
+ {
+ if ( nTextHeight > pData->aSz.Height() )
+ pData->aSz.Height() = nTextHeight;
+
+ pData->aSz.Width() = nTextWidth + 4*nExtra;
+ aSz.Width() += pData->aSz.Width();
+ }
+ else
+ pData->aSz.Height() = Max( Max( nTextHeight, pData->aSz.Height() ), nMinMenuItemHeight );
+
+ nWidth += nTextWidth;
+ }
+
+ // Accel
+ if ( !bIsMenuBar && pData->aAccelKey.GetCode() && !ImplAccelDisabled() )
+ {
+ String aName = pData->aAccelKey.GetName();
+ long nAccWidth = pWin->GetTextWidth( aName );
+ nAccWidth += nExtra;
+ nWidth += nAccWidth;
+ }
+
+ // SubMenu?
+ if ( !bIsMenuBar && pData->pSubMenu )
+ {
+ if ( nFontHeight > nWidth )
+ nWidth += nFontHeight;
+
+ pData->aSz.Height() = Max( Max( nFontHeight, pData->aSz.Height() ), nMinMenuItemHeight );
+ }
+
+ pData->aSz.Height() += EXTRAITEMHEIGHT; // Etwas mehr Abstand:
+
+ if ( !bIsMenuBar )
+ aSz.Height() += (long)pData->aSz.Height();
+
+ if ( nWidth > nMaxWidth )
+ nMaxWidth = nWidth;
+
+ }
+ }
+
+ if ( !bIsMenuBar )
+ {
+ USHORT gfxExtra = (USHORT) Max( nExtra, 7L ); // #107710# increase space between checkmarks/images/text
+ nCheckPos = (USHORT)nExtra;
+ if (nMenuFlags & MENU_FLAG_SHOWCHECKIMAGES)
+ {
+ long nImgOrChkWidth = 0;
+ nImagePos = nCheckPos;
+ if( nMax > 0 ) // NWF case
+ nImgOrChkWidth = nMax + nExtra;
+ else // non NWF case
+ nImgOrChkWidth = nFontHeight/2 + gfxExtra;
+ nImgOrChkWidth = Max( nImgOrChkWidth, aMaxImgSz.Width() + gfxExtra );
+ nTextPos = (USHORT)(nImagePos + nImgOrChkWidth);
+ }
+ else
+ {
+ nImagePos = nCheckPos;
+ nTextPos = (USHORT)(nImagePos + Max( aMaxImgSz.Width(), nCheckWidth ));
+ }
+ nTextPos = nTextPos + gfxExtra;
+
+ aSz.Width() = nTextPos + nMaxWidth + nExtra;
+ aSz.Width() += 4*nExtra; // a _little_ more ...
+
+ int nOuterSpace = ImplGetSVData()->maNWFData.mnMenuFormatExtraBorder;
+ aSz.Width() += 2*nOuterSpace;
+ aSz.Height() += 2*nOuterSpace;
+ }
+ else
+ {
+ nTextPos = (USHORT)(2*nExtra);
+ aSz.Height() = nFontHeight+6;
+
+ // get menubar height from native methods if supported
+ if( pWindow->IsNativeControlSupported( CTRL_MENUBAR, PART_ENTIRE_CONTROL ) )
+ {
+ ImplControlValue aVal;
+ Rectangle aNativeBounds;
+ Rectangle aNativeContent;
+ Point tmp( 0, 0 );
+ Rectangle aCtrlRegion( tmp, Size( 100, 15 ) );
+ if( pWindow->GetNativeControlRegion( ControlType(CTRL_MENUBAR),
+ ControlPart(PART_ENTIRE_CONTROL),
+ aCtrlRegion,
+ ControlState(CTRL_STATE_ENABLED),
+ aVal,
+ OUString(),
+ aNativeBounds,
+ aNativeContent )
+ )
+ {
+ int nNativeHeight = aNativeBounds.GetHeight();
+ if( nNativeHeight > aSz.Height() )
+ aSz.Height() = nNativeHeight;
+ }
+ }
+
+ // account for the size of the close button, which actually is a toolbox
+ // due to NWF this is variable
+ long nCloserHeight = ((MenuBarWindow*) pWindow)->MinCloseButtonSize().Height();
+ if( aSz.Height() < nCloserHeight )
+ aSz.Height() = nCloserHeight;
+ }
+
+ if ( pLogo )
+ aSz.Width() += pLogo->aBitmap.GetSizePixel().Width();
+
+ return aSz;
+}
+
+static void ImplPaintCheckBackground( Window* i_pWindow, const Rectangle& i_rRect, bool i_bHighlight )
+{
+ BOOL bNativeOk = FALSE;
+ if( i_pWindow->IsNativeControlSupported( CTRL_TOOLBAR, PART_BUTTON ) )
+ {
+ ImplControlValue aControlValue;
+ Rectangle aCtrlRegion( i_rRect );
+ ControlState nState = CTRL_STATE_PRESSED | CTRL_STATE_ENABLED;
+
+ aControlValue.setTristateVal( BUTTONVALUE_ON );
+
+ bNativeOk = i_pWindow->DrawNativeControl( CTRL_TOOLBAR, PART_BUTTON,
+ aCtrlRegion, nState, aControlValue,
+ rtl::OUString() );
+ }
+
+ if( ! bNativeOk )
+ {
+ const StyleSettings& rSettings = i_pWindow->GetSettings().GetStyleSettings();
+ Color aColor( i_bHighlight ? rSettings.GetMenuHighlightTextColor() : rSettings.GetHighlightColor() );
+ i_pWindow->DrawSelectionBackground( i_rRect, 0, i_bHighlight, TRUE, FALSE, 2, NULL, &aColor );
+ }
+}
+
+void Menu::ImplPaint( Window* pWin, USHORT nBorder, long nStartY, MenuItemData* pThisItemOnly, BOOL bHighlighted, bool bLayout ) const
+{
+ // Fuer Symbole: nFontHeight x nFontHeight
+ long nFontHeight = pWin->GetTextHeight();
+ long nExtra = nFontHeight/4;
+
+ long nCheckHeight = 0, nRadioHeight = 0, nMaxCheckWidth = 0;
+ ImplGetNativeCheckAndRadioSize( pWin, nCheckHeight, nRadioHeight, nMaxCheckWidth );
+
+ DecorationView aDecoView( pWin );
+ const StyleSettings& rSettings = pWin->GetSettings().GetStyleSettings();
+
+ Point aTopLeft, aTmpPos;
+
+ if ( pLogo )
+ aTopLeft.X() = pLogo->aBitmap.GetSizePixel().Width();
+
+ int nOuterSpace = 0;
+ if( !bIsMenuBar )
+ {
+ nOuterSpace = ImplGetSVData()->maNWFData.mnMenuFormatExtraBorder;
+ aTopLeft.X() += nOuterSpace;
+ aTopLeft.Y() += nOuterSpace;
+ }
+
+ Size aOutSz = pWin->GetOutputSizePixel();
+ USHORT nCount = (USHORT)pItemList->Count();
+ if( bLayout )
+ mpLayoutData->m_aVisibleItemBoundRects.clear();
+ for ( USHORT n = 0; n < nCount; n++ )
+ {
+ MenuItemData* pData = pItemList->GetDataFromPos( n );
+ if ( ImplIsVisible( n ) && ( !pThisItemOnly || ( pData == pThisItemOnly ) ) )
+ {
+ if ( pThisItemOnly && bHighlighted )
+ pWin->SetTextColor( rSettings.GetMenuHighlightTextColor() );
+
+ Point aPos( aTopLeft );
+ aPos.Y() += nBorder;
+ aPos.Y() += nStartY;
+
+ if ( aPos.Y() >= 0 )
+ {
+ long nTextOffsetY = ((pData->aSz.Height()-nFontHeight)/2);
+ if( bIsMenuBar )
+ nTextOffsetY += (aOutSz.Height()-pData->aSz.Height()) / 2;
+ USHORT nTextStyle = 0;
+ USHORT nSymbolStyle = 0;
+ USHORT nImageStyle = 0;
+ // SubMenus ohne Items werden nicht mehr disablte dargestellt,
+ // wenn keine Items enthalten sind, da die Anwendung selber
+ // darauf achten muss. Ansonsten gibt es Faelle, wo beim
+ // asyncronen laden die Eintraege disablte dargestellt werden.
+ if ( !pData->bEnabled )
+ {
+ nTextStyle |= TEXT_DRAW_DISABLE;
+ nSymbolStyle |= SYMBOL_DRAW_DISABLE;
+ nImageStyle |= IMAGE_DRAW_DISABLE;
+ }
+
+ // Separator
+ if ( !bLayout && !bIsMenuBar && ( pData->eType == MENUITEM_SEPARATOR ) )
+ {
+ aTmpPos.Y() = aPos.Y() + ((pData->aSz.Height()-2)/2);
+ aTmpPos.X() = aPos.X() + 2 + nOuterSpace;
+ pWin->SetLineColor( rSettings.GetShadowColor() );
+ pWin->DrawLine( aTmpPos, Point( aOutSz.Width() - 3 - 2*nOuterSpace, aTmpPos.Y() ) );
+ aTmpPos.Y()++;
+ pWin->SetLineColor( rSettings.GetLightColor() );
+ pWin->DrawLine( aTmpPos, Point( aOutSz.Width() - 3 - 2*nOuterSpace, aTmpPos.Y() ) );
+ pWin->SetLineColor();
+ }
+
+ Rectangle aOuterCheckRect( Point( aPos.X()+nCheckPos, aPos.Y() ), Size( pData->aSz.Height(), pData->aSz.Height() ) );
+ aOuterCheckRect.Left() += 1;
+ aOuterCheckRect.Right() -= 1;
+ aOuterCheckRect.Top() += 1;
+ aOuterCheckRect.Bottom() -= 1;
+
+ // CheckMark
+ if ( !bLayout && !bIsMenuBar && pData->HasCheck() )
+ {
+ // draw selection transparent marker if checked
+ // onto that either a checkmark or the item image
+ // will be painted
+ // however do not do this if native checks will be painted since
+ // the selection color too often does not fit the theme's check and/or radio
+
+ if( ! ( ( pData->eType == MENUITEM_IMAGE ) || ( pData->eType == MENUITEM_STRINGIMAGE ) ) )
+ {
+ if ( pWin->IsNativeControlSupported( CTRL_MENU_POPUP,
+ (pData->nBits & MIB_RADIOCHECK)
+ ? PART_MENU_ITEM_CHECK_MARK
+ : PART_MENU_ITEM_RADIO_MARK ) )
+ {
+ ControlPart nPart = ((pData->nBits & MIB_RADIOCHECK)
+ ? PART_MENU_ITEM_RADIO_MARK
+ : PART_MENU_ITEM_CHECK_MARK);
+
+ ControlState nState = 0;
+
+ if ( pData->bChecked )
+ nState |= CTRL_STATE_PRESSED;
+
+ if ( pData->bEnabled )
+ nState |= CTRL_STATE_ENABLED;
+
+ if ( bHighlighted )
+ nState |= CTRL_STATE_SELECTED;
+
+ long nCtrlHeight = (pData->nBits & MIB_RADIOCHECK) ? nCheckHeight : nRadioHeight;
+ aTmpPos.X() = aOuterCheckRect.Left() + (aOuterCheckRect.GetWidth() - nCtrlHeight)/2;
+ aTmpPos.Y() = aOuterCheckRect.Top() + (aOuterCheckRect.GetHeight() - nCtrlHeight)/2;
+
+ Rectangle aCheckRect( aTmpPos, Size( nCtrlHeight, nCtrlHeight ) );
+ pWin->DrawNativeControl( CTRL_MENU_POPUP, nPart,
+ aCheckRect,
+ nState,
+ ImplControlValue(),
+ OUString() );
+ }
+ else if ( pData->bChecked ) // by default do nothing for unchecked items
+ {
+ ImplPaintCheckBackground( pWin, aOuterCheckRect, pThisItemOnly && bHighlighted );
+
+ SymbolType eSymbol;
+ Size aSymbolSize;
+ if ( pData->nBits & MIB_RADIOCHECK )
+ {
+ eSymbol = SYMBOL_RADIOCHECKMARK;
+ aSymbolSize = Size( nFontHeight/2, nFontHeight/2 );
+ }
+ else
+ {
+ eSymbol = SYMBOL_CHECKMARK;
+ aSymbolSize = Size( (nFontHeight*25)/40, nFontHeight/2 );
+ }
+ aTmpPos.X() = aOuterCheckRect.Left() + (aOuterCheckRect.GetWidth() - aSymbolSize.Width())/2;
+ aTmpPos.Y() = aOuterCheckRect.Top() + (aOuterCheckRect.GetHeight() - aSymbolSize.Height())/2;
+ Rectangle aRect( aTmpPos, aSymbolSize );
+ aDecoView.DrawSymbol( aRect, eSymbol, pWin->GetTextColor(), nSymbolStyle );
+ }
+ }
+ }
+
+ // Image:
+ if ( !bLayout && !bIsMenuBar && ( ( pData->eType == MENUITEM_IMAGE ) || ( pData->eType == MENUITEM_STRINGIMAGE ) ) )
+ {
+ // Don't render an image for a check thing
+ if ((nMenuFlags & MENU_FLAG_SHOWCHECKIMAGES) || !pData->HasCheck() )
+ {
+ if( pData->bChecked )
+ ImplPaintCheckBackground( pWin, aOuterCheckRect, pThisItemOnly && bHighlighted );
+ aTmpPos = aOuterCheckRect.TopLeft();
+ aTmpPos.X() += (aOuterCheckRect.GetWidth()-pData->aImage.GetSizePixel().Width())/2;
+ aTmpPos.Y() += (aOuterCheckRect.GetHeight()-pData->aImage.GetSizePixel().Height())/2;
+ pWin->DrawImage( aTmpPos, pData->aImage, nImageStyle );
+ }
+ }
+
+ // Text:
+ if ( ( pData->eType == MENUITEM_STRING ) || ( pData->eType == MENUITEM_STRINGIMAGE ) )
+ {
+ aTmpPos.X() = aPos.X() + nTextPos;
+ aTmpPos.Y() = aPos.Y();
+ aTmpPos.Y() += nTextOffsetY;
+ USHORT nStyle = nTextStyle|TEXT_DRAW_MNEMONIC;
+ if ( pData->bIsTemporary )
+ nStyle |= TEXT_DRAW_DISABLE;
+ MetricVector* pVector = bLayout ? &mpLayoutData->m_aUnicodeBoundRects : NULL;
+ String* pDisplayText = bLayout ? &mpLayoutData->m_aDisplayText : NULL;
+ if( bLayout )
+ {
+ mpLayoutData->m_aLineIndices.push_back( mpLayoutData->m_aDisplayText.Len() );
+ mpLayoutData->m_aLineItemIds.push_back( pData->nId );
+ mpLayoutData->m_aLineItemPositions.push_back( n );
+ }
+ // #i47946# with NWF painted menus the background is transparent
+ // since DrawCtrlText can depend on the background (e.g. for
+ // TEXT_DRAW_DISABLE), temporarily set a background which
+ // hopefully matches the NWF background since it is read
+ // from the system style settings
+ bool bSetTmpBackground = !pWin->IsBackground() && pWin->IsNativeControlSupported( CTRL_MENU_POPUP, PART_ENTIRE_CONTROL );
+ if( bSetTmpBackground )
+ {
+ Color aBg = bIsMenuBar ?
+ pWin->GetSettings().GetStyleSettings().GetMenuBarColor() :
+ pWin->GetSettings().GetStyleSettings().GetMenuColor();
+ pWin->SetBackground( Wallpaper( aBg ) );
+ }
+ pWin->DrawCtrlText( aTmpPos, pData->aText, 0, pData->aText.Len(), nStyle, pVector, pDisplayText );
+ if( bSetTmpBackground )
+ pWin->SetBackground();
+ }
+
+ // Accel
+ if ( !bLayout && !bIsMenuBar && pData->aAccelKey.GetCode() && !ImplAccelDisabled() )
+ {
+ XubString aAccText = pData->aAccelKey.GetName();
+ aTmpPos.X() = aOutSz.Width() - pWin->GetTextWidth( aAccText );
+ aTmpPos.X() -= 4*nExtra;
+
+ aTmpPos.X() -= nOuterSpace;
+ aTmpPos.Y() = aPos.Y();
+ aTmpPos.Y() += nTextOffsetY;
+ pWin->DrawCtrlText( aTmpPos, aAccText, 0, aAccText.Len(), nTextStyle );
+ }
+
+ // SubMenu?
+ if ( !bLayout && !bIsMenuBar && pData->pSubMenu )
+ {
+ aTmpPos.X() = aOutSz.Width() - nFontHeight + nExtra - nOuterSpace;
+ aTmpPos.Y() = aPos.Y();
+ aTmpPos.Y() += nExtra/2;
+ aTmpPos.Y() += ( pData->aSz.Height() / 2 ) - ( nFontHeight/4 );
+ if ( pData->nBits & MIB_POPUPSELECT )
+ {
+ pWin->SetTextColor( rSettings.GetMenuTextColor() );
+ Point aTmpPos2( aPos );
+ aTmpPos2.X() = aOutSz.Width() - nFontHeight - nFontHeight/4;
+ aDecoView.DrawFrame(
+ Rectangle( aTmpPos2, Size( nFontHeight+nFontHeight/4, pData->aSz.Height() ) ), FRAME_DRAW_GROUP );
+ }
+ aDecoView.DrawSymbol(
+ Rectangle( aTmpPos, Size( nFontHeight/2, nFontHeight/2 ) ),
+ SYMBOL_SPIN_RIGHT, pWin->GetTextColor(), nSymbolStyle );
+// if ( pData->nBits & MIB_POPUPSELECT )
+// {
+// aTmpPos.Y() += nFontHeight/2 ;
+// pWin->SetLineColor( rSettings.GetShadowColor() );
+// pWin->DrawLine( aTmpPos, Point( aTmpPos.X() + nFontHeight/3, aTmpPos.Y() ) );
+// pWin->SetLineColor( rSettings.GetLightColor() );
+// aTmpPos.Y()++;
+// pWin->DrawLine( aTmpPos, Point( aTmpPos.X() + nFontHeight/3, aTmpPos.Y() ) );
+// pWin->SetLineColor();
+// }
+ }
+
+ if ( pThisItemOnly && bHighlighted )
+ {
+ // This restores the normal menu or menu bar text
+ // color for when it is no longer highlighted.
+ if ( bIsMenuBar )
+ pWin->SetTextColor( rSettings.GetMenuBarTextColor() );
+ else
+ pWin->SetTextColor( rSettings.GetMenuTextColor() );
+ }
+ }
+ if( bLayout )
+ {
+ if ( !bIsMenuBar )
+ mpLayoutData->m_aVisibleItemBoundRects[ n ] = Rectangle( aTopLeft, Size( aOutSz.Width(), pData->aSz.Height() ) );
+ else
+ mpLayoutData->m_aVisibleItemBoundRects[ n ] = Rectangle( aTopLeft, pData->aSz );
+ }
+ }
+
+ if ( !bIsMenuBar )
+ {
+ aTopLeft.Y() += pData->aSz.Height();
+ }
+ else
+ {
+ aTopLeft.X() += pData->aSz.Width();
+ }
+ }
+
+ if ( !bLayout && !pThisItemOnly && pLogo )
+ {
+ Size aLogoSz = pLogo->aBitmap.GetSizePixel();
+
+ Rectangle aRect( Point( 0, 0 ), Point( aLogoSz.Width()-1, aOutSz.Height() ) );
+ if ( pWin->GetColorCount() >= 256 )
+ {
+ Gradient aGrad( GRADIENT_LINEAR, pLogo->aStartColor, pLogo->aEndColor );
+ aGrad.SetAngle( 1800 );
+ aGrad.SetBorder( 15 );
+ pWin->DrawGradient( aRect, aGrad );
+ }
+ else
+ {
+ pWin->SetFillColor( pLogo->aStartColor );
+ pWin->DrawRect( aRect );
+ }
+
+ Point aLogoPos( 0, aOutSz.Height() - aLogoSz.Height() );
+ pLogo->aBitmap.Draw( pWin, aLogoPos );
+ }
+}
+
+Menu* Menu::ImplGetStartMenu()
+{
+ Menu* pStart = this;
+ while ( pStart && pStart->pStartedFrom && ( pStart->pStartedFrom != pStart ) )
+ pStart = pStart->pStartedFrom;
+ return pStart;
+}
+
+void Menu::ImplCallHighlight( USHORT nHighlightedItem )
+{
+ ImplMenuDelData aDelData( this );
+
+ nSelectedId = 0;
+ MenuItemData* pData = pItemList->GetDataFromPos( nHighlightedItem );
+ if ( pData )
+ nSelectedId = pData->nId;
+ ImplCallEventListeners( VCLEVENT_MENU_HIGHLIGHT, GetItemPos( GetCurItemId() ) );
+
+ if( !aDelData.isDeleted() )
+ {
+ Highlight();
+ nSelectedId = 0;
+ }
+}
+
+IMPL_LINK( Menu, ImplCallSelect, Menu*, EMPTYARG )
+{
+ nEventId = 0;
+ Select();
+ return 0;
+}
+
+Menu* Menu::ImplFindSelectMenu()
+{
+ Menu* pSelMenu = nEventId ? this : NULL;
+
+ for ( ULONG n = GetItemList()->Count(); n && !pSelMenu; )
+ {
+ MenuItemData* pData = GetItemList()->GetDataFromPos( --n );
+
+ if ( pData->pSubMenu )
+ pSelMenu = pData->pSubMenu->ImplFindSelectMenu();
+ }
+
+ return pSelMenu;
+}
+
+Menu* Menu::ImplFindMenu( USHORT nItemId )
+{
+ Menu* pSelMenu = NULL;
+
+ for ( ULONG n = GetItemList()->Count(); n && !pSelMenu; )
+ {
+ MenuItemData* pData = GetItemList()->GetDataFromPos( --n );
+
+ if( pData->nId == nItemId )
+ pSelMenu = this;
+ else if ( pData->pSubMenu )
+ pSelMenu = pData->pSubMenu->ImplFindMenu( nItemId );
+ }
+
+ return pSelMenu;
+}
+
+void Menu::RemoveDisabledEntries( BOOL bCheckPopups, BOOL bRemoveEmptyPopups )
+{
+ for ( USHORT n = 0; n < GetItemCount(); n++ )
+ {
+ BOOL bRemove = FALSE;
+ MenuItemData* pItem = pItemList->GetDataFromPos( n );
+ if ( pItem->eType == MENUITEM_SEPARATOR )
+ {
+ if ( !n || ( GetItemType( n-1 ) == MENUITEM_SEPARATOR ) )
+ bRemove = TRUE;
+ }
+ else
+ bRemove = !pItem->bEnabled;
+
+ if ( bCheckPopups && pItem->pSubMenu )
+ {
+ pItem->pSubMenu->RemoveDisabledEntries( TRUE );
+ if ( bRemoveEmptyPopups && !pItem->pSubMenu->GetItemCount() )
+ bRemove = TRUE;
+ }
+
+ if ( bRemove )
+ RemoveItem( n-- );
+ }
+
+ if ( GetItemCount() )
+ {
+ USHORT nLast = GetItemCount() - 1;
+ MenuItemData* pItem = pItemList->GetDataFromPos( nLast );
+ if ( pItem->eType == MENUITEM_SEPARATOR )
+ RemoveItem( nLast );
+ }
+ delete mpLayoutData, mpLayoutData = NULL;
+}
+
+BOOL Menu::HasValidEntries( BOOL bCheckPopups )
+{
+ BOOL bValidEntries = FALSE;
+ USHORT nCount = GetItemCount();
+ for ( USHORT n = 0; !bValidEntries && ( n < nCount ); n++ )
+ {
+ MenuItemData* pItem = pItemList->GetDataFromPos( n );
+ if ( pItem->bEnabled && ( pItem->eType != MENUITEM_SEPARATOR ) )
+ {
+ if ( bCheckPopups && pItem->pSubMenu )
+ bValidEntries = pItem->pSubMenu->HasValidEntries( TRUE );
+ else
+ bValidEntries = TRUE;
+ }
+ }
+ return bValidEntries;
+}
+
+void Menu::SetLogo( const MenuLogo& rLogo )
+{
+ delete pLogo;
+ pLogo = new MenuLogo( rLogo );
+}
+
+void Menu::SetLogo()
+{
+ delete pLogo;
+ pLogo = NULL;
+}
+
+MenuLogo Menu::GetLogo() const
+{
+ MenuLogo aLogo;
+ if ( pLogo )
+ aLogo = *pLogo;
+ return aLogo;
+}
+
+void Menu::ImplKillLayoutData() const
+{
+ delete mpLayoutData, mpLayoutData = NULL;
+}
+
+void Menu::ImplFillLayoutData() const
+{
+ if( pWindow && pWindow->IsReallyVisible() )
+ {
+ mpLayoutData = new MenuLayoutData();
+ if( bIsMenuBar )
+ {
+ ImplPaint( pWindow, 0, 0, 0, FALSE, true );
+ }
+ else
+ {
+ MenuFloatingWindow* pFloat = (MenuFloatingWindow*)pWindow;
+ ImplPaint( pWindow, pFloat->nScrollerHeight, pFloat->ImplGetStartY(), 0, FALSE, true );
+ }
+ }
+}
+
+String Menu::GetDisplayText() const
+{
+ if( ! mpLayoutData )
+ ImplFillLayoutData();
+ return mpLayoutData ? mpLayoutData->m_aDisplayText : String();
+}
+
+Rectangle Menu::GetCharacterBounds( USHORT nItemID, long nIndex ) const
+{
+ long nItemIndex = -1;
+ if( ! mpLayoutData )
+ ImplFillLayoutData();
+ if( mpLayoutData )
+ {
+ for( size_t i = 0; i < mpLayoutData->m_aLineItemIds.size(); i++ )
+ {
+ if( mpLayoutData->m_aLineItemIds[i] == nItemID )
+ {
+ nItemIndex = mpLayoutData->m_aLineIndices[i];
+ break;
+ }
+ }
+ }
+ return (mpLayoutData && nItemIndex != -1) ? mpLayoutData->GetCharacterBounds( nItemIndex+nIndex ) : Rectangle();
+}
+
+
+long Menu::GetIndexForPoint( const Point& rPoint, USHORT& rItemID ) const
+{
+ long nIndex = -1;
+ rItemID = 0;
+ if( ! mpLayoutData )
+ ImplFillLayoutData();
+ if( mpLayoutData )
+ {
+ nIndex = mpLayoutData->GetIndexForPoint( rPoint );
+ for( size_t i = 0; i < mpLayoutData->m_aLineIndices.size(); i++ )
+ {
+ if( mpLayoutData->m_aLineIndices[i] <= nIndex &&
+ (i == mpLayoutData->m_aLineIndices.size()-1 || mpLayoutData->m_aLineIndices[i+1] > nIndex) )
+ {
+ // make index relative to item
+ nIndex -= mpLayoutData->m_aLineIndices[i];
+ rItemID = mpLayoutData->m_aLineItemIds[i];
+ break;
+ }
+ }
+ }
+ return nIndex;
+}
+
+long Menu::GetLineCount() const
+{
+ if( ! mpLayoutData )
+ ImplFillLayoutData();
+ return mpLayoutData ? mpLayoutData->GetLineCount() : 0;
+}
+
+Pair Menu::GetLineStartEnd( long nLine ) const
+{
+ if( ! mpLayoutData )
+ ImplFillLayoutData();
+ return mpLayoutData ? mpLayoutData->GetLineStartEnd( nLine ) : Pair( -1, -1 );
+}
+
+Pair Menu::GetItemStartEnd( USHORT nItem ) const
+{
+ if( ! mpLayoutData )
+ ImplFillLayoutData();
+
+ for( size_t i = 0; i < mpLayoutData->m_aLineItemIds.size(); i++ )
+ if( mpLayoutData->m_aLineItemIds[i] == nItem )
+ return GetLineStartEnd( i );
+
+ return Pair( -1, -1 );
+}
+
+USHORT Menu::GetDisplayItemId( long nLine ) const
+{
+ USHORT nItemId = 0;
+ if( ! mpLayoutData )
+ ImplFillLayoutData();
+ if( mpLayoutData && ( nLine >= 0 ) && ( nLine < (long)mpLayoutData->m_aLineItemIds.size() ) )
+ nItemId = mpLayoutData->m_aLineItemIds[nLine];
+ return nItemId;
+}
+
+BOOL Menu::ConvertPoint( Point& rPoint, Window* pReferenceWindow ) const
+{
+ BOOL bRet = FALSE;
+ if( pWindow && pReferenceWindow )
+ {
+ rPoint = pReferenceWindow->OutputToAbsoluteScreenPixel( rPoint );
+ rPoint = pWindow->AbsoluteScreenToOutputPixel( rPoint );
+ bRet = TRUE;
+ }
+ return bRet;
+}
+
+Rectangle Menu::GetBoundingRectangle( USHORT nPos ) const
+{
+ Rectangle aRet;
+
+ if( ! mpLayoutData )
+ ImplFillLayoutData();
+ if( mpLayoutData )
+ {
+ std::map< USHORT, Rectangle >::const_iterator it = mpLayoutData->m_aVisibleItemBoundRects.find( nPos );
+ if( it != mpLayoutData->m_aVisibleItemBoundRects.end() )
+ aRet = it->second;
+ }
+ return aRet;
+}
+
+void Menu::SetAccessibleName( USHORT nItemId, const XubString& rStr )
+{
+ USHORT nPos;
+ MenuItemData* pData = pItemList->GetData( nItemId, nPos );
+
+ if ( pData && !rStr.Equals( pData->aAccessibleName ) )
+ {
+ pData->aAccessibleName = rStr;
+ ImplCallEventListeners( VCLEVENT_MENU_ACCESSIBLENAMECHANGED, nPos );
+ }
+}
+
+XubString Menu::GetAccessibleName( USHORT nItemId ) const
+{
+ MenuItemData* pData = pItemList->GetData( nItemId );
+
+ if ( pData )
+ return pData->aAccessibleName;
+ else
+ return ImplGetSVEmptyStr();
+}
+
+void Menu::SetAccessibleDescription( USHORT nItemId, const XubString& rStr )
+{
+ MenuItemData* pData = pItemList->GetData( nItemId );
+
+ if ( pData )
+ pData->aAccessibleDescription = rStr;
+}
+
+XubString Menu::GetAccessibleDescription( USHORT nItemId ) const
+{
+ MenuItemData* pData = pItemList->GetData( nItemId );
+
+ if ( pData )
+ return pData->aAccessibleDescription;
+ else
+ return ImplGetSVEmptyStr();
+}
+
+void Menu::ImplSetSalMenu( SalMenu *pSalMenu )
+{
+ if( mpSalMenu )
+ ImplGetSVData()->mpDefInst->DestroyMenu( mpSalMenu );
+ mpSalMenu = pSalMenu;
+}
+
+BOOL Menu::GetSystemMenuData( SystemMenuData* pData ) const
+{
+ Menu* pMenu = (Menu*)this;
+ if( pData && pMenu->ImplGetSalMenu() )
+ {
+ pMenu->ImplGetSalMenu()->GetSystemMenuData( pData );
+ return TRUE;
+ }
+ else
+ return FALSE;
+}
+
+bool Menu::IsHighlighted( USHORT nItemPos ) const
+{
+ bool bRet = false;
+
+ if( pWindow )
+ {
+ if( bIsMenuBar )
+ bRet = ( nItemPos == static_cast< MenuBarWindow * > (pWindow)->GetHighlightedItem() );
+ else
+ bRet = ( nItemPos == static_cast< MenuFloatingWindow * > (pWindow)->GetHighlightedItem() );
+ }
+
+ return bRet;
+}
+
+void Menu::HighlightItem( USHORT nItemPos )
+{
+ if ( pWindow )
+ {
+ if ( bIsMenuBar )
+ {
+ MenuBarWindow* pMenuWin = static_cast< MenuBarWindow* >( pWindow );
+ pMenuWin->SetAutoPopup( FALSE );
+ pMenuWin->ChangeHighlightItem( nItemPos, FALSE );
+ }
+ else
+ {
+ static_cast< MenuFloatingWindow* >( pWindow )->ChangeHighlightItem( nItemPos, FALSE );
+ }
+ }
+}
+
+// -----------
+// - MenuBar -
+// -----------
+
+MenuBar::MenuBar() : Menu( TRUE )
+{
+ mbDisplayable = TRUE;
+ mbCloserVisible = FALSE;
+ mbFloatBtnVisible = FALSE;
+ mbHideBtnVisible = FALSE;
+}
+
+MenuBar::MenuBar( const MenuBar& rMenu ) : Menu( TRUE )
+{
+ mbDisplayable = TRUE;
+ mbCloserVisible = FALSE;
+ mbFloatBtnVisible = FALSE;
+ mbHideBtnVisible = FALSE;
+ *this = rMenu;
+ bIsMenuBar = TRUE;
+}
+
+MenuBar::MenuBar( const ResId& rResId ) : Menu ( TRUE )
+{
+ mbDisplayable = TRUE;
+ mbCloserVisible = FALSE;
+ mbFloatBtnVisible = FALSE;
+ mbHideBtnVisible = FALSE;
+ ImplLoadRes( rResId );
+}
+
+MenuBar::~MenuBar()
+{
+ ImplDestroy( this, TRUE );
+}
+
+void MenuBar::ShowCloser( BOOL bShow )
+{
+ ShowButtons( bShow, mbFloatBtnVisible, mbHideBtnVisible );
+}
+
+void MenuBar::ShowFloatButton( BOOL bShow )
+{
+ ShowButtons( mbCloserVisible, bShow, mbHideBtnVisible );
+}
+
+void MenuBar::ShowHideButton( BOOL bShow )
+{
+ ShowButtons( mbCloserVisible, mbFloatBtnVisible, bShow );
+}
+
+void MenuBar::ShowButtons( BOOL bClose, BOOL bFloat, BOOL bHide )
+{
+ if ( (bClose != mbCloserVisible) ||
+ (bFloat != mbFloatBtnVisible) ||
+ (bHide != mbHideBtnVisible) )
+ {
+ mbCloserVisible = bClose;
+ mbFloatBtnVisible = bFloat;
+ mbHideBtnVisible = bHide;
+ if ( ImplGetWindow() )
+ ((MenuBarWindow*)ImplGetWindow())->ShowButtons( bClose, bFloat, bHide );
+ }
+}
+
+void MenuBar::SetDisplayable( BOOL bDisplayable )
+{
+ if( bDisplayable != mbDisplayable )
+ {
+ mbDisplayable = bDisplayable;
+ MenuBarWindow* pMenuWin = (MenuBarWindow*) ImplGetWindow();
+ if( pMenuWin )
+ pMenuWin->ImplLayoutChanged();
+ }
+}
+
+Window* MenuBar::ImplCreate( Window* pParent, Window* pWindow, MenuBar* pMenu )
+{
+ if ( !pWindow )
+ pWindow = new MenuBarWindow( pParent );
+
+ pMenu->pStartedFrom = 0;
+ pMenu->pWindow = pWindow;
+ ((MenuBarWindow*)pWindow)->SetMenu( pMenu );
+ long nHeight = pMenu->ImplCalcSize( pWindow ).Height();
+
+ // depending on the native implementation or the displayable flag
+ // the menubar windows is supressed (ie, height=0)
+ if( !((MenuBar*) pMenu)->IsDisplayable() ||
+ ( pMenu->ImplGetSalMenu() && pMenu->ImplGetSalMenu()->VisibleMenuBar() ) )
+ nHeight = 0;
+
+ pWindow->SetPosSizePixel( 0, 0, 0, nHeight, WINDOW_POSSIZE_HEIGHT );
+ return pWindow;
+}
+
+void MenuBar::ImplDestroy( MenuBar* pMenu, BOOL bDelete )
+{
+ MenuBarWindow* pWindow = (MenuBarWindow*) pMenu->ImplGetWindow();
+ if ( pWindow && bDelete )
+ {
+ pWindow->KillActivePopup();
+ delete pWindow;
+ }
+ pMenu->pWindow = NULL;
+}
+
+BOOL MenuBar::ImplHandleKeyEvent( const KeyEvent& rKEvent, BOOL bFromMenu )
+{
+ BOOL bDone = FALSE;
+
+ // No keyboard processing when system handles the menu or our menubar is invisible
+ if( !IsDisplayable() ||
+ ( ImplGetSalMenu() && ImplGetSalMenu()->VisibleMenuBar() ) )
+ return bDone;
+
+ // Enabled-Abfragen, falls diese Methode von einem anderen Fenster gerufen wurde...
+ Window* pWin = ImplGetWindow();
+ if ( pWin && pWin->IsEnabled() && pWin->IsInputEnabled() && ! pWin->IsInModalMode() )
+ bDone = ((MenuBarWindow*)pWin)->ImplHandleKeyEvent( rKEvent, bFromMenu );
+ return bDone;
+}
+
+// -----------------------------------------------------------------------
+
+void MenuBar::SelectEntry( USHORT nId )
+{
+ MenuBarWindow* pMenuWin = (MenuBarWindow*) ImplGetWindow();
+
+ if( pMenuWin )
+ {
+ pMenuWin->GrabFocus();
+ nId = GetItemPos( nId );
+
+ // #99705# popup the selected menu
+ pMenuWin->SetAutoPopup( TRUE );
+ if( ITEMPOS_INVALID != pMenuWin->nHighlightedItem )
+ {
+ pMenuWin->KillActivePopup();
+ pMenuWin->ChangeHighlightItem( ITEMPOS_INVALID, FALSE );
+ }
+ if( nId != ITEMPOS_INVALID )
+ pMenuWin->ChangeHighlightItem( nId, FALSE );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+// handler for native menu selection and command events
+
+BOOL MenuBar::HandleMenuActivateEvent( Menu *pMenu ) const
+{
+ if( pMenu )
+ {
+ ImplMenuDelData aDelData( this );
+
+ pMenu->pStartedFrom = (Menu*)this;
+ pMenu->bInCallback = TRUE;
+ pMenu->Activate();
+
+ if( !aDelData.isDeleted() )
+ pMenu->bInCallback = FALSE;
+ }
+ return TRUE;
+}
+
+BOOL MenuBar::HandleMenuDeActivateEvent( Menu *pMenu ) const
+{
+ if( pMenu )
+ {
+ ImplMenuDelData aDelData( this );
+
+ pMenu->pStartedFrom = (Menu*)this;
+ pMenu->bInCallback = TRUE;
+ pMenu->Deactivate();
+ if( !aDelData.isDeleted() )
+ pMenu->bInCallback = FALSE;
+ }
+ return TRUE;
+}
+
+BOOL MenuBar::HandleMenuHighlightEvent( Menu *pMenu, USHORT nHighlightEventId ) const
+{
+ if( !pMenu )
+ pMenu = ((Menu*) this)->ImplFindMenu( nHighlightEventId );
+ if( pMenu )
+ {
+ ImplMenuDelData aDelData( pMenu );
+
+ if( mnHighlightedItemPos != ITEMPOS_INVALID )
+ pMenu->ImplCallEventListeners( VCLEVENT_MENU_DEHIGHLIGHT, mnHighlightedItemPos );
+
+ if( !aDelData.isDeleted() )
+ {
+ pMenu->mnHighlightedItemPos = pMenu->GetItemPos( nHighlightEventId );
+ pMenu->nSelectedId = nHighlightEventId;
+ pMenu->pStartedFrom = (Menu*)this;
+ pMenu->ImplCallHighlight( pMenu->mnHighlightedItemPos );
+ }
+ return TRUE;
+ }
+ else
+ return FALSE;
+}
+
+BOOL MenuBar::HandleMenuCommandEvent( Menu *pMenu, USHORT nCommandEventId ) const
+{
+ if( !pMenu )
+ pMenu = ((Menu*) this)->ImplFindMenu( nCommandEventId );
+ if( pMenu )
+ {
+ pMenu->nSelectedId = nCommandEventId;
+ pMenu->pStartedFrom = (Menu*)this;
+ pMenu->ImplSelect();
+ return TRUE;
+ }
+ else
+ return FALSE;
+}
+
+USHORT MenuBar::AddMenuBarButton( const Image& i_rImage, const Link& i_rLink, USHORT i_nPos )
+{
+ return AddMenuBarButton( i_rImage, i_rLink, String(), i_nPos );
+}
+
+USHORT MenuBar::AddMenuBarButton( const Image& i_rImage, const Link& i_rLink, const String& i_rToolTip, USHORT i_nPos )
+{
+ return pWindow ? static_cast<MenuBarWindow*>(pWindow)->AddMenuBarButton( i_rImage, i_rLink, i_rToolTip, i_nPos ) : 0;
+}
+
+void MenuBar::SetMenuBarButtonHighlightHdl( USHORT nId, const Link& rLink )
+{
+ if( pWindow )
+ static_cast<MenuBarWindow*>(pWindow)->SetMenuBarButtonHighlightHdl( nId, rLink );
+}
+
+Rectangle MenuBar::GetMenuBarButtonRectPixel( USHORT nId )
+{
+ return pWindow ? static_cast<MenuBarWindow*>(pWindow)->GetMenuBarButtonRectPixel( nId ) : Rectangle();
+}
+
+void MenuBar::RemoveMenuBarButton( USHORT nId )
+{
+ if( pWindow )
+ static_cast<MenuBarWindow*>(pWindow)->RemoveMenuBarButton( nId );
+}
+
+BOOL MenuBar::HandleMenuButtonEvent( Menu *, USHORT i_nButtonId ) const
+{
+ return static_cast<MenuBarWindow*>(pWindow)->HandleMenuButtonEvent( i_nButtonId );
+}
+
+// -----------------------------------------------------------------------
+
+// BOOL PopupMenu::bAnyPopupInExecute = FALSE;
+
+PopupMenu::PopupMenu()
+{
+ pRefAutoSubMenu = NULL;
+}
+
+PopupMenu::PopupMenu( const ResId& rResId )
+{
+ pRefAutoSubMenu = NULL;
+ ImplLoadRes( rResId );
+}
+
+PopupMenu::PopupMenu( const PopupMenu& rMenu ) : Menu()
+{
+ pRefAutoSubMenu = NULL;
+ *this = rMenu;
+}
+
+PopupMenu::~PopupMenu()
+{
+ if( pRefAutoSubMenu && *pRefAutoSubMenu == this )
+ *pRefAutoSubMenu = NULL; // #111060# avoid second delete in ~MenuItemData
+}
+
+BOOL PopupMenu::IsInExecute()
+{
+ return GetActivePopupMenu() ? TRUE : FALSE;
+}
+
+PopupMenu* PopupMenu::GetActivePopupMenu()
+{
+ ImplSVData* pSVData = ImplGetSVData();
+ return pSVData->maAppData.mpActivePopupMenu;
+}
+
+void PopupMenu::EndExecute( USHORT nSelectId )
+{
+ if ( ImplGetWindow() )
+ ImplGetFloatingWindow()->EndExecute( nSelectId );
+}
+
+void PopupMenu::SelectEntry( USHORT nId )
+{
+ if ( ImplGetWindow() )
+ {
+ if( nId != ITEMPOS_INVALID )
+ {
+ USHORT nPos;
+ MenuItemData* pData = GetItemList()->GetData( nId, nPos );
+ if ( pData->pSubMenu )
+ ImplGetFloatingWindow()->ChangeHighlightItem( nPos, TRUE );
+ else
+ ImplGetFloatingWindow()->EndExecute( nId );
+ }
+ else
+ {
+ MenuFloatingWindow* pFloat = ImplGetFloatingWindow();
+ pFloat->GrabFocus();
+ USHORT nPos;
+ for( nPos = 0; nPos < GetItemList()->Count(); nPos++ )
+ {
+ MenuItemData* pData = (MenuItemData*)GetItemList()->GetObject( nPos );
+ if( pData->pSubMenu )
+ {
+ pFloat->KillActivePopup();
+ }
+ }
+ pFloat->ChangeHighlightItem( ITEMPOS_INVALID, FALSE );
+ }
+ }
+}
+
+void PopupMenu::SetSelectedEntry( USHORT nId )
+{
+ nSelectedId = nId;
+}
+
+USHORT PopupMenu::Execute( Window* pExecWindow, const Point& rPopupPos )
+{
+ return Execute( pExecWindow, Rectangle( rPopupPos, rPopupPos ), POPUPMENU_EXECUTE_DOWN );
+}
+
+USHORT PopupMenu::Execute( Window* pExecWindow, const Rectangle& rRect, USHORT nFlags )
+{
+ ENSURE_OR_RETURN( pExecWindow, "PopupMenu::Execute: need a non-NULL window!", 0 );
+
+
+ ULONG nPopupModeFlags = 0;
+ if ( nFlags & POPUPMENU_EXECUTE_DOWN )
+ nPopupModeFlags = FLOATWIN_POPUPMODE_DOWN;
+ else if ( nFlags & POPUPMENU_EXECUTE_UP )
+ nPopupModeFlags = FLOATWIN_POPUPMODE_UP;
+ else if ( nFlags & POPUPMENU_EXECUTE_LEFT )
+ nPopupModeFlags = FLOATWIN_POPUPMODE_LEFT;
+ else if ( nFlags & POPUPMENU_EXECUTE_RIGHT )
+ nPopupModeFlags = FLOATWIN_POPUPMODE_RIGHT;
+ else
+ nPopupModeFlags = FLOATWIN_POPUPMODE_DOWN;
+
+ if (nFlags & POPUPMENU_NOMOUSEUPCLOSE ) // allow popup menus to stay open on mouse button up
+ nPopupModeFlags |= FLOATWIN_POPUPMODE_NOMOUSEUPCLOSE; // useful if the menu was opened on mousebutton down (eg toolbox configuration)
+
+ return ImplExecute( pExecWindow, rRect, nPopupModeFlags, 0, FALSE );
+}
+
+USHORT PopupMenu::ImplExecute( Window* pW, const Rectangle& rRect, ULONG nPopupModeFlags, Menu* pSFrom, BOOL bPreSelectFirst )
+{
+ if ( !pSFrom && ( PopupMenu::IsInExecute() || !GetItemCount() ) )
+ return 0;
+
+ delete mpLayoutData, mpLayoutData = NULL;
+
+ ImplSVData* pSVData = ImplGetSVData();
+
+ pStartedFrom = pSFrom;
+ nSelectedId = 0;
+ bCanceled = FALSE;
+
+ ULONG nFocusId = 0;
+ BOOL bRealExecute = FALSE;
+ if ( !pStartedFrom )
+ {
+ pSVData->maWinData.mbNoDeactivate = TRUE;
+ nFocusId = Window::SaveFocus();
+ bRealExecute = TRUE;
+ }
+ else
+ {
+ // assure that only one menu is open at a time
+ if( pStartedFrom->bIsMenuBar && pSVData->maWinData.mpFirstFloat )
+ pSVData->maWinData.mpFirstFloat->EndPopupMode( FLOATWIN_POPUPMODEEND_CANCEL | FLOATWIN_POPUPMODEEND_CLOSEALL );
+ }
+
+ DBG_ASSERT( !ImplGetWindow(), "Win?!" );
+ Rectangle aRect( rRect );
+ aRect.SetPos( pW->OutputToScreenPixel( aRect.TopLeft() ) );
+
+ WinBits nStyle = WB_BORDER;
+ if ( bRealExecute )
+ nPopupModeFlags |= FLOATWIN_POPUPMODE_NEWLEVEL;
+ if ( !pStartedFrom || !pStartedFrom->bIsMenuBar )
+ nPopupModeFlags |= FLOATWIN_POPUPMODE_PATHMOUSECANCELCLICK | FLOATWIN_POPUPMODE_ALLMOUSEBUTTONCLOSE;
+
+ nPopupModeFlags |= FLOATWIN_POPUPMODE_NOKEYCLOSE;
+
+ // Kann beim Debuggen hilfreich sein.
+ // nPopupModeFlags |= FLOATWIN_POPUPMODE_NOFOCUSCLOSE;
+
+ ImplDelData aDelData;
+ pW->ImplAddDel( &aDelData );
+
+ bInCallback = TRUE; // hier schon setzen, falls Activate ueberladen
+ Activate();
+ bInCallback = FALSE;
+
+ if ( aDelData.IsDelete() )
+ return 0; // Error
+
+ pW->ImplRemoveDel( &aDelData );
+
+ if ( bCanceled || bKilled )
+ return 0;
+
+ if ( !GetItemCount() )
+ return 0;
+
+ // Das Flag MENU_FLAG_HIDEDISABLEDENTRIES wird vererbt.
+ if ( pSFrom )
+ {
+ if ( pSFrom->nMenuFlags & MENU_FLAG_HIDEDISABLEDENTRIES )
+ nMenuFlags |= MENU_FLAG_HIDEDISABLEDENTRIES;
+ else
+ nMenuFlags &= ~MENU_FLAG_HIDEDISABLEDENTRIES;
+ }
+ else
+ // #102790# context menues shall never show disabled entries
+ nMenuFlags |= MENU_FLAG_HIDEDISABLEDENTRIES;
+
+
+ USHORT nVisibleEntries = ImplGetVisibleItemCount();
+ if ( !nVisibleEntries )
+ {
+ ResMgr* pResMgr = ImplGetResMgr();
+ if( pResMgr )
+ {
+ String aTmpEntryText( ResId( SV_RESID_STRING_NOSELECTIONPOSSIBLE, *pResMgr ) );
+ MenuItemData* pData = pItemList->Insert(
+ 0xFFFF, MENUITEM_STRING, 0, aTmpEntryText, Image(), NULL, 0xFFFF );
+ pData->bIsTemporary = TRUE;
+ }
+ }
+ else if ( Application::GetSettings().GetStyleSettings().GetAutoMnemonic() && !( nMenuFlags & MENU_FLAG_NOAUTOMNEMONICS ) )
+ {
+ CreateAutoMnemonics();
+ }
+
+ MenuFloatingWindow* pWin = new MenuFloatingWindow( this, pW, nStyle | WB_SYSTEMWINDOW );
+ if( pSVData->maNWFData.mbFlatMenu )
+ pWin->SetBorderStyle( WINDOW_BORDER_NOBORDER );
+ else
+ pWin->SetBorderStyle( pWin->GetBorderStyle() | WINDOW_BORDER_MENU );
+ pWindow = pWin;
+
+ Size aSz = ImplCalcSize( pWin );
+
+ long nMaxHeight = pWin->GetDesktopRectPixel().GetHeight();
+ if( Application::GetScreenCount() > 1 && ! Application::IsMultiDisplay() )
+ {
+ Window* pDeskW = pWindow->GetWindow( WINDOW_REALPARENT );
+ if( ! pDeskW )
+ pDeskW = pWindow;
+ Point aDesktopTL( pDeskW->OutputToAbsoluteScreenPixel( aRect.TopLeft() ) );
+ nMaxHeight = Application::GetWorkAreaPosSizePixel(
+ Application::GetBestScreen( Rectangle( aDesktopTL, aRect.GetSize() ) )
+ ).GetHeight();
+ }
+ if ( pStartedFrom && pStartedFrom->bIsMenuBar )
+ nMaxHeight -= pW->GetSizePixel().Height();
+ sal_Int32 nLeft, nTop, nRight, nBottom;
+ pWindow->GetBorder( nLeft, nTop, nRight, nBottom );
+ nMaxHeight -= nTop+nBottom;
+ if ( aSz.Height() > nMaxHeight )
+ {
+ pWin->EnableScrollMenu( TRUE );
+ USHORT nStart = ImplGetFirstVisible();
+ USHORT nEntries = ImplCalcVisEntries( nMaxHeight, nStart );
+ aSz.Height() = ImplCalcHeight( nEntries );
+ }
+
+ pWin->SetFocusId( nFocusId );
+ pWin->SetOutputSizePixel( aSz );
+ // #102158# menus must never grab the focus, otherwise
+ // they will be closed immediately
+ // from now on focus grabbing is only prohibited automatically if
+ // FLOATWIN_POPUPMODE_GRABFOCUS was set (which is done below), because some
+ // floaters (like floating toolboxes) may grab the focus
+ // pWin->GrabFocus();
+ if ( GetItemCount() )
+ {
+ SalMenu* pMenu = ImplGetSalMenu();
+ if( pMenu && bRealExecute && pMenu->ShowNativePopupMenu( pWin, aRect, nPopupModeFlags | FLOATWIN_POPUPMODE_GRABFOCUS ) )
+ {
+ pWin->StopExecute(0);
+ pWin->doShutdown();
+ pWindow->doLazyDelete();
+ pWindow = NULL;
+ return nSelectedId;
+ }
+ else
+ {
+ pWin->StartPopupMode( aRect, nPopupModeFlags | FLOATWIN_POPUPMODE_GRABFOCUS );
+ }
+ if( pSFrom )
+ {
+ USHORT aPos;
+ if( pSFrom->bIsMenuBar )
+ aPos = ((MenuBarWindow *) pSFrom->pWindow)->GetHighlightedItem();
+ else
+ aPos = ((MenuFloatingWindow *) pSFrom->pWindow)->GetHighlightedItem();
+
+ pWin->SetPosInParent( aPos ); // store position to be sent in SUBMENUDEACTIVATE
+ pSFrom->ImplCallEventListeners( VCLEVENT_MENU_SUBMENUACTIVATE, aPos );
+ }
+ }
+ if ( bPreSelectFirst )
+ {
+ USHORT nCount = (USHORT)pItemList->Count();
+ for ( USHORT n = 0; n < nCount; n++ )
+ {
+ MenuItemData* pData = pItemList->GetDataFromPos( n );
+ if ( ( pData->bEnabled || !Application::GetSettings().GetStyleSettings().GetSkipDisabledInMenus() )
+ && ( pData->eType != MENUITEM_SEPARATOR ) && ImplIsVisible( n ) && ImplIsSelectable( n ) )
+ {
+ pWin->ChangeHighlightItem( n, FALSE );
+ break;
+ }
+ }
+ }
+ if ( bRealExecute )
+ {
+ pWin->ImplAddDel( &aDelData );
+
+ ImplDelData aModalWinDel;
+ pW->ImplAddDel( &aModalWinDel );
+ pW->ImplIncModalCount();
+
+ pWin->Execute();
+
+ DBG_ASSERT( ! aModalWinDel.IsDead(), "window for popup died, modal count incorrect !" );
+ if( ! aModalWinDel.IsDead() )
+ pW->ImplDecModalCount();
+
+ if ( !aDelData.IsDelete() )
+ pWin->ImplRemoveDel( &aDelData );
+ else
+ return 0;
+
+ // Focus wieder herstellen (kann schon im Select wieder
+ // hergestellt wurden sein
+ nFocusId = pWin->GetFocusId();
+ if ( nFocusId )
+ {
+ pWin->SetFocusId( 0 );
+ pSVData->maWinData.mbNoDeactivate = FALSE;
+ }
+ pWin->ImplEndPopupMode( 0, nFocusId );
+
+ if ( nSelectedId ) // Dann abraeumen... ( sonst macht TH das )
+ {
+ PopupMenu* pSub = pWin->GetActivePopup();
+ while ( pSub )
+ {
+ pSub->ImplGetFloatingWindow()->EndPopupMode();
+ pSub = pSub->ImplGetFloatingWindow()->GetActivePopup();
+ }
+ }
+ pWin->doShutdown();
+ pWindow->doLazyDelete();
+ pWindow = NULL;
+
+ // Steht noch ein Select aus?
+ Menu* pSelect = ImplFindSelectMenu();
+ if ( pSelect )
+ {
+ // Beim Popup-Menu muss das Select vor dem Verlassen von Execute gerufen werden!
+ Application::RemoveUserEvent( pSelect->nEventId );
+ pSelect->nEventId = 0;
+ pSelect->Select();
+ }
+ }
+
+ return bRealExecute ? nSelectedId : 0;
+}
+
+USHORT PopupMenu::ImplCalcVisEntries( long nMaxHeight, USHORT nStartEntry, USHORT* pLastVisible ) const
+{
+ nMaxHeight -= 2 * ImplGetFloatingWindow()->GetScrollerHeight();
+
+ long nHeight = 0;
+ USHORT nEntries = (USHORT) pItemList->Count();
+ USHORT nVisEntries = 0;
+
+ if ( pLastVisible )
+ *pLastVisible = 0;
+
+ for ( USHORT n = nStartEntry; n < nEntries; n++ )
+ {
+ if ( ImplIsVisible( n ) )
+ {
+ MenuItemData* pData = pItemList->GetDataFromPos( n );
+ nHeight += pData->aSz.Height();
+ if ( nHeight > nMaxHeight )
+ break;
+
+ if ( pLastVisible )
+ *pLastVisible = n;
+ nVisEntries++;
+ }
+ }
+ return nVisEntries;
+}
+
+long PopupMenu::ImplCalcHeight( USHORT nEntries ) const
+{
+ long nHeight = 0;
+
+ USHORT nFound = 0;
+ for ( USHORT n = 0; ( nFound < nEntries ) && ( n < pItemList->Count() ); n++ )
+ {
+ if ( ImplIsVisible( (USHORT) n ) )
+ {
+ MenuItemData* pData = pItemList->GetDataFromPos( n );
+ nHeight += pData->aSz.Height();
+ nFound++;
+ }
+ }
+
+ nHeight += 2*ImplGetFloatingWindow()->GetScrollerHeight();
+
+ 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 )
+ {
+ 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;
+// nStartY = 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 );
+
+ if( !bKeyInput && pMenu && pMenu->pStartedFrom && !pMenu->pStartedFrom->bIsMenuBar )
+ {
+ // #102461# remove highlight in parent
+ MenuItemData* pData;
+ USHORT i, nCount = (USHORT)pMenu->pStartedFrom->pItemList->Count();
+ 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()
+{
+ ImplInitClipRegion();
+}
+
+long MenuFloatingWindow::ImplGetStartY() const
+{
+ long nY = 0;
+ if( pMenu )
+ {
+ for ( USHORT 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::ImplInitClipRegion()
+{
+ if ( IsScrollMenu() )
+ {
+ SetClipRegion( ImplCalcClipRegion() );
+ }
+ else
+ {
+ SetClipRegion();
+ }
+}
+
+void MenuFloatingWindow::ImplHighlightItem( const MouseEvent& rMEvt, BOOL bMBDown )
+{
+ if( ! pMenu )
+ return;
+
+ long nY = nScrollerHeight;
+ long nMouseY = rMEvt.GetPosPixel().Y();
+ Size aOutSz = GetOutputSizePixel();
+ if ( ( nMouseY >= nY ) && ( nMouseY < ( aOutSz.Height() - nY ) ) )
+ {
+ BOOL bHighlighted = FALSE;
+ USHORT nCount = (USHORT)pMenu->pItemList->Count();
+ nY += ImplGetStartY(); // ggf. gescrollt.
+ for ( USHORT 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 )
+ {
+ // Nur wenn ueber dem Pfeil geklickt wurde...
+ Size aSz = GetOutputSizePixel();
+ long nFontHeight = GetTextHeight();
+ bPopupArea = ( rMEvt.GetPosPixel().X() >= ( aSz.Width() - nFontHeight - nFontHeight/4 ) );
+ }
+
+ if ( bMBDown )
+ {
+ if ( n != nHighlightedItem )
+ {
+ ChangeHighlightItem( (USHORT)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( (USHORT)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( MenuFloatingWindow, PopupEnd, FloatingWindow*, EMPTYARG )
+{
+ // "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 )
+ {
+ // Wenn dies Fenster von TH geschlossen wurde, hat noch ein anderes
+ // Menu dieses Fenster als pActivePopup.
+ if ( pMenu->pStartedFrom )
+ {
+ // Das pWin am 'Parent' kann aber schon 0 sein, falls die Kette von
+ // vorne abgeraeumt wurde und jetzt die EndPopup-Events eintrudeln
+ 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( MenuFloatingWindow, AutoScroll, Timer*, EMPTYARG )
+{
+ 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 ) )
+ {
+ 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 ( ULONG n = 0; n < nHighlightedItem; n++ )
+ {
+ pData = pMenu->pItemList->GetDataFromPos( n );
+ nY += pData->aSz.Height();
+ }
+ pData = pMenu->pItemList->GetDataFromPos( nHighlightedItem );
+ Size MySize = GetOutputSizePixel();
+// Point MyPos = GetPosPixel();
+// Point aItemTopLeft( MyPos.X(), MyPos.Y()+nY );
+ Point aItemTopLeft( 0, nY );
+ Point aItemBottomRight( aItemTopLeft );
+ aItemBottomRight.X() += MySize.Width();
+ aItemBottomRight.Y() += pData->aSz.Height();
+
+ // Popups leicht versetzen:
+ 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: Wegen Abstuerzen durch Reschedule() im Aufruf von Activate()
+ // Ausserdem wird damit auch verhindert, dass SubMenus angezeigt werden,
+ // die lange im Activate Rescheduled haben und jetzt schon nicht mehr
+ // angezeigt werden sollen.
+ Menu* pTest = pActivePopup;
+ ULONG nOldFlags = GetPopupModeFlags();
+ SetPopupModeFlags( GetPopupModeFlags() | FLOATWIN_POPUPMODE_NOAPPFOCUSCLOSE );
+ USHORT 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( MenuFloatingWindow, SubmenuClose, Timer*, EMPTYARG )
+{
+ 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 ? (USHORT) GetSettings().GetStyleSettings().GetScrollBarSize() /2 : 0;
+ bScrollDown = TRUE;
+ ImplInitClipRegion();
+}
+
+void MenuFloatingWindow::Execute()
+{
+ ImplSVData* pSVData = ImplGetSVData();
+
+ pSVData->maAppData.mpActivePopupMenu = (PopupMenu*)pMenu;
+
+ bInExecute = TRUE;
+// bCallingSelect = FALSE;
+
+ while ( bInExecute )
+ Application::Yield();
+
+ pSVData->maAppData.mpActivePopupMenu = NULL;
+
+// while ( bCallingSelect )
+// Application::Yield();
+}
+
+void MenuFloatingWindow::StopExecute( ULONG nFocusId )
+{
+ // Focus wieder herstellen
+ // (kann schon im Select wieder hergestellt wurden sein)
+ 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;
+
+ // Vor allen Aktionen schon pActivePopup = 0, falls z.B.
+ // PopupModeEndHdl des zu zerstoerenden Popups mal synchron gerufen wird.
+ 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;
+ 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;
+ }
+ }
+
+ // Wenn von woanders gestartet, dann ab dort aufraumen:
+ 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;
+
+ // Dies Fenster wird gleich zerstoert => Daten lokal merken...
+ Menu* pM = pMenu;
+ USHORT 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( USHORT nId )
+{
+ USHORT nPos;
+ if ( pMenu && pMenu->GetItemList()->GetData( nId, nPos ) )
+ nHighlightedItem = nPos;
+ else
+ nHighlightedItem = ITEMPOS_INVALID;
+
+ EndExecute();
+}
+
+void MenuFloatingWindow::MouseButtonDown( const MouseEvent& rMEvt )
+{
+ // TH macht ein ToTop auf dieses Fenster, aber das aktive Popup
+ // soll oben bleiben...
+ // due to focus chage this would close all menues -> 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 in lokaler Variable merken und gleich zuruecksetzen,
+ // weil nach EndExecute zu spaet
+ USHORT _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 ) )
+ {
+ // Nicht wenn ueber dem Pfeil geklickt wurde...
+ 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() )
+ {
+#ifdef OS2
+ if ( ImplHilite(rMEvt) )
+ {
+#endif
+ // #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 );
+#ifdef OS2
+ }
+#endif
+
+ if ( IsScrollMenu() )
+ ImplScroll( rMEvt.GetPosPixel() );
+ }
+ else
+#ifdef OS2
+ if ( ImplHilite(rMEvt) )
+#endif
+ {
+ 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();
+
+// nStartY += nEntryHeight;
+
+ 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();
+ USHORT nLastVisible;
+ ((PopupMenu*)pMenu)->ImplCalcVisEntries( nHeight, nFirstEntry, &nLastVisible );
+ if ( pMenu->ImplGetNextVisible( nLastVisible ) == ITEMPOS_INVALID )
+ {
+ bScrollDown = FALSE;
+ ImplDrawScroller( FALSE );
+ }
+
+// nStartY -= nEntryHeight;
+ 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(); // Falls durch MouseMove gescrollt.
+ 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( USHORT n, BOOL bStartPopupTimer )
+{
+ // #57934# ggf. das aktive Popup sofort schliessen, damit TH's Hintergrundsicherung funktioniert.
+ // #65750# Dann verzichten wir lieber auf den schmalen Streifen Hintergrundsicherung.
+ // Sonst lassen sich die Menus schlecht bedienen.
+// 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 = (USHORT)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;
+ USHORT i, nCount = (USHORT)pMenu->pStartedFrom->pItemList->Count();
+ 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->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( USHORT nPos, BOOL bHighlight )
+{
+ if( ! pMenu )
+ return;
+
+ Size aSz = GetOutputSizePixel();
+ long nStartY = ImplGetStartY();
+ long nY = nScrollerHeight+nStartY;
+ long nX = 0;
+
+ if ( pMenu->pLogo )
+ nX = pMenu->pLogo->aBitmap.GetSizePixel().Width();
+
+ int nOuterSpace = ImplGetSVData()->maNWFData.mnMenuFormatExtraBorder;
+ nY += nOuterSpace;
+
+ USHORT nCount = (USHORT)pMenu->pItemList->Count();
+ for ( USHORT 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+nOuterSpace, nY ), Size( aSz.Width()-2*nOuterSpace, 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() ) );
+ DrawNativeControl( CTRL_MENU_POPUP, PART_ENTIRE_CONTROL,
+ aCtrlRect,
+ CTRL_STATE_ENABLED,
+ ImplControlValue(),
+ OUString() );
+ if( bHighlight &&
+ IsNativeControlSupported( CTRL_MENU_POPUP, PART_MENU_ITEM ) )
+ {
+ bDrawItemRect = false;
+ if( FALSE == DrawNativeControl( CTRL_MENU_POPUP, PART_MENU_ITEM,
+ aItemRect,
+ CTRL_STATE_SELECTED | ( pData->bEnabled? CTRL_STATE_ENABLED: 0 ),
+ ImplControlValue(),
+ 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( USHORT 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();
+
+ USHORT nCount = (USHORT)pMenu->pItemList->Count();
+ for ( USHORT 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();
+
+ USHORT n = nHighlightedItem;
+ if ( n == ITEMPOS_INVALID )
+ {
+ if ( bUp )
+ n = 0;
+ else
+ n = pMenu->GetItemCount()-1;
+ }
+
+ USHORT nLoop = n;
+
+ if( bHomeEnd )
+ {
+ // absolute positioning
+ if( bUp )
+ {
+ n = pMenu->GetItemCount();
+ nLoop = n-1;
+ }
+ else
+ {
+ n = (USHORT)-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 ) )
+ {
+ // Selektion noch im sichtbaren Bereich?
+ if ( IsScrollMenu() )
+ {
+ ChangeHighlightItem( ITEMPOS_INVALID, FALSE );
+
+ while ( n < nFirstEntry )
+ ImplScroll( TRUE );
+
+ Size aOutSz = GetOutputSizePixel();
+ USHORT 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 );
+
+ USHORT 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();
+ }
+ }
+ }
+ 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:
+ {
+ xub_Unicode nCharCode = rKEvent.GetCharCode();
+ USHORT nPos = 0;
+ USHORT 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
+ {
+ // Bei ungueltigen Tasten Beepen, aber nicht bei HELP und F-Tasten
+ if ( !rKEvent.GetKeyCode().IsMod2() && ( nCode != KEY_HELP ) && ( rKEvent.GetKeyCode().GetGroup() != KEYGROUP_FKEYS ) )
+ Sound::Beep();
+ FloatingWindow::KeyInput( rKEvent );
+ }
+ }
+ }
+ // #105474# check if menu window was not destroyed
+ if ( !aDelData.IsDelete() )
+ {
+ 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;
+ DrawNativeControl( CTRL_MENU_POPUP, PART_ENTIRE_CONTROL,
+ Rectangle( Point( nX, 0 ), aPxSize ),
+ CTRL_STATE_ENABLED,
+ ImplControlValue(),
+ OUString() );
+ ImplInitClipRegion();
+ }
+ 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;
+
+ USHORT nStyle = 0;
+ if ( ( bUp && !bScrollUp ) || ( !bUp && !bScrollDown ) )
+ nStyle |= SYMBOL_DRAW_DISABLE;
+
+ aDecoView.DrawSymbol( aRect, eSymbol, GetSettings().GetStyleSettings().GetButtonTextColor(), nStyle );
+
+ ImplInitClipRegion();
+}
+
+void MenuFloatingWindow::RequestHelp( const HelpEvent& rHEvt )
+{
+ USHORT 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 ),
+ aFloatBtn( this, WB_NOPOINTERFOCUS | WB_SMALLSTYLE | WB_RECTSTYLE ),
+ aHideBtn( this, WB_NOPOINTERFOCUS | WB_SMALLSTYLE | WB_RECTSTYLE )
+{
+ SetType( WINDOW_MENUBARWINDOW );
+ pMenu = NULL;
+ pActivePopup = NULL;
+ nSaveFocusId = 0;
+ nHighlightedItem = ITEMPOS_INVALID;
+ mbAutoPopup = TRUE;
+ nSaveFocusId = 0;
+ bIgnoreFirstMove = TRUE;
+ bStayActive = FALSE;
+
+ ResMgr* pResMgr = ImplGetResMgr();
+
+ if( pResMgr )
+ {
+ BitmapEx aBitmap( ResId( SV_RESID_BITMAP_CLOSEDOC, *pResMgr ) );
+ BitmapEx aBitmapHC( ResId( SV_RESID_BITMAP_CLOSEDOCHC, *pResMgr ) );
+
+ aCloser.maImage = Image( aBitmap );
+ aCloser.maImageHC = Image( aBitmapHC );
+
+ aCloser.SetOutStyle( TOOLBOX_STYLE_FLAT );
+ aCloser.SetBackground();
+ aCloser.SetPaintTransparent( TRUE );
+ aCloser.SetParentClipMode( PARENTCLIPMODE_NOCLIP );
+
+ aCloser.InsertItem( IID_DOCUMENTCLOSE,
+ GetSettings().GetStyleSettings().GetHighContrastMode() ? aCloser.maImageHC : aCloser.maImage, 0 );
+ aCloser.SetSelectHdl( LINK( this, MenuBarWindow, CloserHdl ) );
+ aCloser.AddEventListener( LINK( this, MenuBarWindow, ToolboxEventHdl ) );
+ aCloser.SetQuickHelpText( IID_DOCUMENTCLOSE, XubString( ResId( SV_HELPTEXT_CLOSEDOCUMENT, *pResMgr ) ) );
+
+ aFloatBtn.SetClickHdl( LINK( this, MenuBarWindow, FloatHdl ) );
+ aFloatBtn.SetSymbol( SYMBOL_FLOAT );
+ aFloatBtn.SetQuickHelpText( XubString( ResId( SV_HELPTEXT_RESTORE, *pResMgr ) ) );
+
+ aHideBtn.SetClickHdl( LINK( this, MenuBarWindow, HideHdl ) );
+ aHideBtn.SetSymbol( SYMBOL_HIDE );
+ aHideBtn.SetQuickHelpText( XubString( ResId( SV_HELPTEXT_MINIMIZE, *pResMgr ) ) );
+ }
+
+ ImplInitStyleSettings();
+
+ AddEventListener( LINK( this, MenuBarWindow, ShowHideListener ) );
+}
+
+MenuBarWindow::~MenuBarWindow()
+{
+ aCloser.RemoveEventListener( LINK( this, MenuBarWindow, ToolboxEventHdl ) );
+ RemoveEventListener( LINK( this, MenuBarWindow, ShowHideListener ) );
+}
+
+void MenuBarWindow::SetMenu( MenuBar* pMen )
+{
+ pMenu = pMen;
+ KillActivePopup();
+ nHighlightedItem = ITEMPOS_INVALID;
+ ImplInitMenuWindow( this, TRUE, TRUE );
+ if ( pMen )
+ {
+ aCloser.ShowItem( IID_DOCUMENTCLOSE, pMen->HasCloser() );
+ aCloser.Show( pMen->HasCloser() || !m_aAddButtons.empty() );
+ aFloatBtn.Show( pMen->HasFloatButton() );
+ aHideBtn.Show( pMen->HasHideButton() );
+ }
+ Invalidate();
+
+ // show and connect native menubar
+ if( pMenu && pMenu->ImplGetSalMenu() )
+ {
+ if( pMenu->ImplGetSalMenu()->VisibleMenuBar() )
+ ImplGetFrame()->SetMenu( pMenu->ImplGetSalMenu() );
+
+ pMenu->ImplGetSalMenu()->SetFrame( ImplGetFrame() );
+ }
+}
+
+void MenuBarWindow::ShowButtons( BOOL bClose, BOOL bFloat, BOOL bHide )
+{
+ aCloser.ShowItem( IID_DOCUMENTCLOSE, bClose );
+ aCloser.Show( bClose || ! m_aAddButtons.empty() );
+ aFloatBtn.Show( bFloat );
+ aHideBtn.Show( bHide );
+ Resize();
+}
+
+Size MenuBarWindow::MinCloseButtonSize()
+{
+ return aCloser.getMinSize();
+}
+
+IMPL_LINK( MenuBarWindow, CloserHdl, PushButton*, EMPTYARG )
+{
+ if( ! pMenu )
+ return 0;
+
+ if( aCloser.GetCurItemId() == IID_DOCUMENTCLOSE )
+ {
+ // #i106052# call close hdl asynchronously to ease handler implementation
+ // this avoids still being in the handler while the DecoToolBox already
+ // gets destroyed
+ Application::PostUserEvent( ((MenuBar*)pMenu)->GetCloserHdl(), pMenu );
+ }
+ else
+ {
+ std::map<USHORT,AddButtonEntry>::iterator it = m_aAddButtons.find( aCloser.GetCurItemId() );
+ if( it != m_aAddButtons.end() )
+ {
+ MenuBar::MenuBarButtonCallbackArg aArg;
+ aArg.nId = it->first;
+ aArg.bHighlight = (aCloser.GetHighlightItemId() == it->first);
+ aArg.pMenuBar = dynamic_cast<MenuBar*>(pMenu);
+ return it->second.m_aSelectLink.Call( &aArg );
+ }
+ }
+ return 0;
+}
+
+IMPL_LINK( MenuBarWindow, ToolboxEventHdl, VclWindowEvent*, pEvent )
+{
+ if( ! pMenu )
+ return 0;
+
+ MenuBar::MenuBarButtonCallbackArg aArg;
+ aArg.nId = 0xffff;
+ aArg.bHighlight = (pEvent->GetId() == VCLEVENT_TOOLBOX_HIGHLIGHT);
+ aArg.pMenuBar = dynamic_cast<MenuBar*>(pMenu);
+ if( pEvent->GetId() == VCLEVENT_TOOLBOX_HIGHLIGHT )
+ aArg.nId = aCloser.GetHighlightItemId();
+ else if( pEvent->GetId() == VCLEVENT_TOOLBOX_HIGHLIGHTOFF )
+ {
+ USHORT nPos = static_cast< USHORT >(reinterpret_cast<sal_IntPtr>(pEvent->GetData()));
+ aArg.nId = aCloser.GetItemId( nPos );
+ }
+ std::map< USHORT, AddButtonEntry >::iterator it = m_aAddButtons.find( aArg.nId );
+ if( it != m_aAddButtons.end() )
+ {
+ it->second.m_aHighlightLink.Call( &aArg );
+ }
+ return 0;
+}
+
+IMPL_LINK( MenuBarWindow, 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;
+}
+
+IMPL_LINK( MenuBarWindow, FloatHdl, PushButton*, EMPTYARG )
+{
+ return pMenu ? ((MenuBar*)pMenu)->GetFloatButtonClickHdl().Call( pMenu ) : 0;
+}
+
+IMPL_LINK( MenuBarWindow, HideHdl, PushButton*, EMPTYARG )
+{
+ return pMenu ? ((MenuBar*)pMenu)->GetHideButtonClickHdl().Call( pMenu ) : 0;
+}
+
+void MenuBarWindow::ImplCreatePopup( BOOL bPreSelectFirst )
+{
+ MenuItemData* pItemData = pMenu ? pMenu->GetItemList()->GetDataFromPos( nHighlightedItem ) : NULL;
+ if ( pItemData )
+ {
+ bIgnoreFirstMove = TRUE;
+ if ( pActivePopup && ( pActivePopup != pItemData->pSubMenu ) )
+ {
+ KillActivePopup();
+ }
+ if ( pItemData->bEnabled && pItemData->pSubMenu && ( nHighlightedItem != ITEMPOS_INVALID ) && ( pItemData->pSubMenu != pActivePopup ) )
+ {
+ pActivePopup = (PopupMenu*)pItemData->pSubMenu;
+ long nX = 0;
+ MenuItemData* pData = 0;
+ for ( ULONG n = 0; n < nHighlightedItem; n++ )
+ {
+ pData = pMenu->GetItemList()->GetDataFromPos( n );
+ nX += pData->aSz.Width();
+ }
+ pData = pMenu->pItemList->GetDataFromPos( nHighlightedItem );
+// Point MyPos = GetPosPixel();
+// Point aItemTopLeft( MyPos.X()+nX, MyPos.Y() );
+ Point aItemTopLeft( nX, 0 );
+ Point aItemBottomRight( aItemTopLeft );
+ aItemBottomRight.X() += pData->aSz.Width();
+
+ // Im Vollbild-Modus hat die MenuBar ggf. die Hoehe 0:
+ // Nicht immer einfach die Window-Hoehe nehmen, weil ItemHeight < WindowHeight.
+ if ( GetSizePixel().Height() )
+ {
+ // #107747# give menuitems the height of the menubar
+ aItemBottomRight.Y() += GetOutputSizePixel().Height()-1;
+ }
+
+ // ImplExecute ist doch nicht modal...
+ // #99071# do not grab the focus, otherwise it will be restored to the menubar
+ // when the frame is reactivated later
+ //GrabFocus();
+ pActivePopup->ImplExecute( this, Rectangle( aItemTopLeft, aItemBottomRight ), FLOATWIN_POPUPMODE_DOWN, pMenu, bPreSelectFirst );
+ if ( pActivePopup )
+ {
+ // Hat kein Window, wenn vorher abgebrochen oder keine Eintraege
+ if ( pActivePopup->ImplGetFloatingWindow() )
+ pActivePopup->ImplGetFloatingWindow()->AddPopupModeWindow( this );
+ else
+ pActivePopup = NULL;
+ }
+ }
+ }
+}
+
+
+void MenuBarWindow::KillActivePopup()
+{
+ if ( pActivePopup )
+ {
+ if( pActivePopup->pWindow != NULL )
+ if( ((FloatingWindow *) pActivePopup->pWindow)->IsInCleanUp() )
+ return; // kill it later
+
+ if ( pActivePopup->bInCallback )
+ pActivePopup->bCanceled = TRUE;
+
+ pActivePopup->bInCallback = TRUE;
+ pActivePopup->Deactivate();
+ pActivePopup->bInCallback = FALSE;
+ // Abfrage auf pActivePopup, falls im Deactivate abgeschossen...
+ if ( pActivePopup && pActivePopup->ImplGetWindow() )
+ {
+ pActivePopup->ImplGetFloatingWindow()->StopExecute();
+ pActivePopup->ImplGetFloatingWindow()->doShutdown();
+ pActivePopup->pWindow->doLazyDelete();
+ pActivePopup->pWindow = NULL;
+ }
+ pActivePopup = 0;
+ }
+}
+
+void MenuBarWindow::PopupClosed( Menu* pPopup )
+{
+ if ( pPopup == pActivePopup )
+ {
+ KillActivePopup();
+ ChangeHighlightItem( ITEMPOS_INVALID, FALSE, ImplGetFrameWindow()->ImplGetFrameData()->mbHasFocus, FALSE );
+ }
+}
+
+void MenuBarWindow::MouseButtonDown( const MouseEvent& rMEvt )
+{
+ mbAutoPopup = TRUE;
+ USHORT nEntry = ImplFindEntry( rMEvt.GetPosPixel() );
+ if ( ( nEntry != ITEMPOS_INVALID ) && ( nEntry != nHighlightedItem ) )
+ {
+ ChangeHighlightItem( nEntry, FALSE );
+ }
+ else
+ {
+ KillActivePopup();
+ ChangeHighlightItem( ITEMPOS_INVALID, FALSE );
+ }
+}
+
+void MenuBarWindow::MouseButtonUp( const MouseEvent& )
+{
+}
+
+void MenuBarWindow::MouseMove( const MouseEvent& rMEvt )
+{
+ // Im Move nur Highlighten, wenn schon eins gehighlightet.
+ if ( rMEvt.IsSynthetic() || rMEvt.IsLeaveWindow() || rMEvt.IsEnterWindow() || ( nHighlightedItem == ITEMPOS_INVALID ) )
+ return;
+
+ if( bIgnoreFirstMove )
+ {
+ bIgnoreFirstMove = FALSE;
+ return;
+ }
+
+ USHORT nEntry = ImplFindEntry( rMEvt.GetPosPixel() );
+ if ( ( nEntry != ITEMPOS_INVALID )
+#ifdef OS2
+ && ( ImplHilite(rMEvt) )
+#endif
+ && ( nEntry != nHighlightedItem ) )
+ ChangeHighlightItem( nEntry, FALSE );
+}
+
+void MenuBarWindow::ChangeHighlightItem( USHORT n, BOOL bSelectEntry, BOOL bAllowRestoreFocus, BOOL bDefaultToDocument)
+{
+ if( ! pMenu )
+ return;
+
+ // #57934# ggf. das aktive Popup sofort schliessen, damit TH's Hintergrundsicherung funktioniert.
+ MenuItemData* pNextData = pMenu->pItemList->GetDataFromPos( n );
+ if ( pActivePopup && pActivePopup->ImplGetWindow() && ( !pNextData || ( pActivePopup != pNextData->pSubMenu ) ) )
+ KillActivePopup(); // pActivePopup ggf. ohne pWin, wenn in Activate() Rescheduled wurde
+
+ // Activate am MenuBar immer nur einmal pro Vorgang...
+ BOOL bJustActivated = FALSE;
+ if ( ( nHighlightedItem == ITEMPOS_INVALID ) && ( n != ITEMPOS_INVALID ) )
+ {
+ ImplGetSVData()->maWinData.mbNoDeactivate = TRUE;
+ if( !bStayActive )
+ {
+ // #105406# avoid saving the focus when we already have the focus
+ BOOL bNoSaveFocus = (this == ImplGetSVData()->maWinData.mpFocusWin );
+
+ if( nSaveFocusId )
+ {
+ if( !ImplGetSVData()->maWinData.mbNoSaveFocus )
+ {
+ // we didn't clean up last time
+ Window::EndSaveFocus( nSaveFocusId, FALSE ); // clean up
+ nSaveFocusId = 0;
+ if( !bNoSaveFocus )
+ nSaveFocusId = Window::SaveFocus(); // only save focus when initially activated
+ }
+ else {
+ ; // do nothing: we 're activated again from taskpanelist, focus was already saved
+ }
+ }
+ else
+ {
+ if( !bNoSaveFocus )
+ nSaveFocusId = Window::SaveFocus(); // only save focus when initially activated
+ }
+ }
+ else
+ bStayActive = FALSE;
+ pMenu->bInCallback = TRUE; // hier schon setzen, falls Activate ueberladen
+ pMenu->Activate();
+ pMenu->bInCallback = FALSE;
+ bJustActivated = TRUE;
+ }
+ else if ( ( nHighlightedItem != ITEMPOS_INVALID ) && ( n == ITEMPOS_INVALID ) )
+ {
+ pMenu->bInCallback = TRUE;
+ pMenu->Deactivate();
+ pMenu->bInCallback = FALSE;
+ ImplGetSVData()->maWinData.mbNoDeactivate = FALSE;
+ if( !ImplGetSVData()->maWinData.mbNoSaveFocus )
+ {
+ ULONG nTempFocusId = nSaveFocusId;
+ nSaveFocusId = 0;
+ Window::EndSaveFocus( nTempFocusId, bAllowRestoreFocus );
+ // #105406# restore focus to document if we could not save focus before
+ if( bDefaultToDocument && !nTempFocusId && bAllowRestoreFocus )
+ GrabFocusToDocument();
+ }
+ }
+
+ if ( nHighlightedItem != ITEMPOS_INVALID )
+ {
+ HighlightItem( nHighlightedItem, FALSE );
+ pMenu->ImplCallEventListeners( VCLEVENT_MENU_DEHIGHLIGHT, nHighlightedItem );
+ }
+
+ nHighlightedItem = (USHORT)n;
+ DBG_ASSERT( ( nHighlightedItem == ITEMPOS_INVALID ) || pMenu->ImplIsVisible( nHighlightedItem ), "ChangeHighlightItem: Not visible!" );
+ HighlightItem( nHighlightedItem, TRUE );
+ pMenu->ImplCallHighlight( nHighlightedItem );
+
+ if( mbAutoPopup )
+ ImplCreatePopup( bSelectEntry );
+
+ // #58935# #73659# Focus, wenn kein Popup drunter haengt...
+ if ( bJustActivated && !pActivePopup )
+ GrabFocus();
+}
+
+void MenuBarWindow::HighlightItem( USHORT nPos, BOOL bHighlight )
+{
+ if( ! pMenu )
+ return;
+
+ long nX = 0;
+ ULONG nCount = pMenu->pItemList->Count();
+ for ( ULONG n = 0; n < nCount; n++ )
+ {
+ MenuItemData* pData = pMenu->pItemList->GetDataFromPos( n );
+ if ( n == nPos )
+ {
+ if ( pData->eType != MENUITEM_SEPARATOR )
+ {
+ // #107747# give menuitems the height of the menubar
+ Rectangle aRect = Rectangle( Point( nX, 1 ), Size( pData->aSz.Width(), GetOutputSizePixel().Height()-2 ) );
+ Push( PUSH_CLIPREGION );
+ IntersectClipRegion( aRect );
+ if ( bHighlight )
+ {
+ if( IsNativeControlSupported( CTRL_MENUBAR, PART_MENU_ITEM ) &&
+ IsNativeControlSupported( CTRL_MENUBAR, PART_ENTIRE_CONTROL ) )
+ {
+ // draw background (transparency)
+ MenubarValue aControlValue;
+ aControlValue.maTopDockingAreaHeight = ImplGetTopDockingAreaHeight( this );
+
+ Point tmp(0,0);
+ Rectangle aBgRegion( tmp, GetOutputSizePixel() );
+ DrawNativeControl( CTRL_MENUBAR, PART_ENTIRE_CONTROL,
+ aBgRegion,
+ CTRL_STATE_ENABLED,
+ aControlValue,
+ OUString() );
+ ImplAddNWFSeparator( this, aControlValue );
+
+ // draw selected item
+ DrawNativeControl( CTRL_MENUBAR, PART_MENU_ITEM,
+ aRect,
+ CTRL_STATE_ENABLED | CTRL_STATE_SELECTED,
+ aControlValue,
+ OUString() );
+ }
+ else
+ {
+ SetFillColor( GetSettings().GetStyleSettings().GetMenuHighlightColor() );
+ SetLineColor();
+ DrawRect( aRect );
+ }
+ }
+ else
+ {
+ if( IsNativeControlSupported( CTRL_MENUBAR, PART_ENTIRE_CONTROL) )
+ {
+ MenubarValue aMenubarValue;
+ aMenubarValue.maTopDockingAreaHeight = ImplGetTopDockingAreaHeight( this );
+
+ // use full window size to get proper gradient
+ // but clip accordingly
+ Point aPt;
+ Rectangle aCtrlRect( aPt, GetOutputSizePixel() );
+
+ DrawNativeControl( CTRL_MENUBAR, PART_ENTIRE_CONTROL, aCtrlRect, CTRL_STATE_ENABLED, aMenubarValue, rtl::OUString() );
+ ImplAddNWFSeparator( this, aMenubarValue );
+ }
+ else
+ Erase( aRect );
+ }
+ Pop();
+ pMenu->ImplPaint( this, 0, 0, pData, bHighlight );
+ }
+ return;
+ }
+
+ nX += pData->aSz.Width();
+ }
+}
+
+Rectangle MenuBarWindow::ImplGetItemRect( USHORT nPos )
+{
+ Rectangle aRect;
+ if( pMenu )
+ {
+ long nX = 0;
+ ULONG nCount = pMenu->pItemList->Count();
+ for ( ULONG n = 0; n < nCount; n++ )
+ {
+ MenuItemData* pData = pMenu->pItemList->GetDataFromPos( n );
+ if ( n == nPos )
+ {
+ if ( pData->eType != MENUITEM_SEPARATOR )
+ // #107747# give menuitems the height of the menubar
+ aRect = Rectangle( Point( nX, 1 ), Size( pData->aSz.Width(), GetOutputSizePixel().Height()-2 ) );
+ break;
+ }
+
+ nX += pData->aSz.Width();
+ }
+ }
+ return aRect;
+}
+
+void MenuBarWindow::KeyInput( const KeyEvent& rKEvent )
+{
+ if ( !ImplHandleKeyEvent( rKEvent ) )
+ Window::KeyInput( rKEvent );
+}
+
+BOOL MenuBarWindow::ImplHandleKeyEvent( const KeyEvent& rKEvent, BOOL bFromMenu )
+{
+ if( ! pMenu )
+ return FALSE;
+
+ if ( pMenu->bInCallback )
+ return TRUE; // schlucken
+
+ BOOL bDone = FALSE;
+ USHORT nCode = rKEvent.GetKeyCode().GetCode();
+
+ if( GetParent() )
+ {
+ if( GetParent()->GetWindow( WINDOW_CLIENT )->IsSystemWindow() )
+ {
+ SystemWindow *pSysWin = (SystemWindow*)GetParent()->GetWindow( WINDOW_CLIENT );
+ if( pSysWin->GetTaskPaneList() )
+ if( pSysWin->GetTaskPaneList()->HandleKeyEvent( rKEvent ) )
+ return TRUE;
+ }
+ }
+
+ if ( nCode == KEY_MENU && !rKEvent.GetKeyCode().IsShift() ) // only F10, not Shift-F10
+ {
+ mbAutoPopup = ImplGetSVData()->maNWFData.mbOpenMenuOnF10;
+ if ( nHighlightedItem == ITEMPOS_INVALID )
+ {
+ ChangeHighlightItem( 0, FALSE );
+ GrabFocus();
+ }
+ else
+ {
+ ChangeHighlightItem( ITEMPOS_INVALID, FALSE );
+ nSaveFocusId = 0;
+ }
+ bDone = TRUE;
+ }
+ else if ( bFromMenu )
+ {
+ if ( ( nCode == KEY_LEFT ) || ( nCode == KEY_RIGHT ) ||
+ ( nCode == KEY_HOME ) || ( nCode == KEY_END ) )
+ {
+ USHORT n = nHighlightedItem;
+ if ( n == ITEMPOS_INVALID )
+ {
+ if ( nCode == KEY_LEFT)
+ n = 0;
+ else
+ n = pMenu->GetItemCount()-1;
+ }
+
+ // handling gtk like (aka mbOpenMenuOnF10)
+ // do not highlight an item when opening a sub menu
+ // unless there already was a higlighted sub menu item
+ bool bWasHighlight = false;
+ if( pActivePopup )
+ {
+ MenuFloatingWindow* pSubWindow = dynamic_cast<MenuFloatingWindow*>(pActivePopup->ImplGetWindow());
+ if( pSubWindow )
+ bWasHighlight = (pSubWindow->GetHighlightedItem() != ITEMPOS_INVALID);
+ }
+
+ USHORT nLoop = n;
+
+ if( nCode == KEY_HOME )
+ { n = (USHORT)-1; nLoop = n+1; }
+ if( nCode == KEY_END )
+ { n = pMenu->GetItemCount(); nLoop = n-1; }
+
+ do
+ {
+ if ( nCode == KEY_LEFT || nCode == KEY_END )
+ {
+ if ( n )
+ n--;
+ else
+ n = pMenu->GetItemCount()-1;
+ }
+ if ( nCode == KEY_RIGHT || nCode == KEY_HOME )
+ {
+ n++;
+ if ( n >= pMenu->GetItemCount() )
+ n = 0;
+ }
+
+ MenuItemData* pData = (MenuItemData*)pMenu->GetItemList()->GetDataFromPos( n );
+ if ( ( pData->eType != MENUITEM_SEPARATOR ) && pMenu->ImplIsVisible( n ) )
+ {
+ BOOL bDoSelect = TRUE;
+ if( ImplGetSVData()->maNWFData.mbOpenMenuOnF10 )
+ bDoSelect = bWasHighlight;
+ ChangeHighlightItem( n, bDoSelect );
+ break;
+ }
+ } while ( n != nLoop );
+ bDone = TRUE;
+ }
+ else if ( nCode == KEY_RETURN )
+ {
+ if( pActivePopup ) KillActivePopup();
+ else
+ if ( !mbAutoPopup )
+ {
+ ImplCreatePopup( TRUE );
+ mbAutoPopup = TRUE;
+ }
+ bDone = TRUE;
+ }
+ else if ( ( nCode == KEY_UP ) || ( nCode == KEY_DOWN ) )
+ {
+ if ( !mbAutoPopup )
+ {
+ ImplCreatePopup( TRUE );
+ mbAutoPopup = TRUE;
+ }
+ bDone = TRUE;
+ }
+ else if ( nCode == KEY_ESCAPE || ( nCode == KEY_F6 && rKEvent.GetKeyCode().IsMod1() ) )
+ {
+ if( pActivePopup )
+ {
+ // bring focus to menu bar without any open popup
+ mbAutoPopup = FALSE;
+ USHORT n = nHighlightedItem;
+ nHighlightedItem = ITEMPOS_INVALID;
+ bStayActive = TRUE;
+ ChangeHighlightItem( n, FALSE );
+ bStayActive = FALSE;
+ KillActivePopup();
+ GrabFocus();
+ }
+ else
+ ChangeHighlightItem( ITEMPOS_INVALID, FALSE );
+
+ if( nCode == KEY_F6 && rKEvent.GetKeyCode().IsMod1() )
+ {
+ // put focus into document
+ GrabFocusToDocument();
+ }
+
+ bDone = TRUE;
+ }
+ }
+
+ if ( !bDone && ( bFromMenu || rKEvent.GetKeyCode().IsMod2() ) )
+ {
+ xub_Unicode nCharCode = rKEvent.GetCharCode();
+ if ( nCharCode )
+ {
+ USHORT nEntry, nDuplicates;
+ MenuItemData* pData = pMenu->GetItemList()->SearchItem( nCharCode, rKEvent.GetKeyCode(), nEntry, nDuplicates, nHighlightedItem );
+ if ( pData && (nEntry != ITEMPOS_INVALID) )
+ {
+ mbAutoPopup = TRUE;
+ ChangeHighlightItem( nEntry, TRUE );
+ bDone = TRUE;
+ }
+ else
+ {
+ // Wegen Systemmenu und anderen System-HotKeys, nur
+ // eigenstaendige Character-Kombinationen auswerten
+ USHORT nKeyCode = rKEvent.GetKeyCode().GetCode();
+ if ( ((nKeyCode >= KEY_A) && (nKeyCode <= KEY_Z)) )
+ Sound::Beep();
+ }
+ }
+ }
+ return bDone;
+}
+
+void MenuBarWindow::Paint( const Rectangle& )
+{
+ if( ! pMenu )
+ return;
+
+ // no VCL paint if native menus
+ if( pMenu->ImplGetSalMenu() && pMenu->ImplGetSalMenu()->VisibleMenuBar() )
+ {
+ ImplGetFrame()->DrawMenuBar();
+ return;
+ }
+
+ if( IsNativeControlSupported( CTRL_MENUBAR, PART_ENTIRE_CONTROL) )
+ {
+ Point aPt;
+ Rectangle aCtrlRegion( aPt, GetOutputSizePixel() );
+
+ MenubarValue aMenubarValue;
+ aMenubarValue.maTopDockingAreaHeight = ImplGetTopDockingAreaHeight( this );
+
+ DrawNativeControl( CTRL_MENUBAR, PART_ENTIRE_CONTROL, aCtrlRegion, CTRL_STATE_ENABLED, aMenubarValue, rtl::OUString() );
+ ImplAddNWFSeparator( this, aMenubarValue );
+ }
+ SetFillColor( GetSettings().GetStyleSettings().GetMenuColor() );
+ pMenu->ImplPaint( this, 0 );
+ if ( nHighlightedItem != ITEMPOS_INVALID )
+ HighlightItem( nHighlightedItem, TRUE );
+
+ // in high contrast mode draw a separating line on the lower edge
+ if( ! IsNativeControlSupported( CTRL_MENUBAR, PART_ENTIRE_CONTROL) &&
+ GetSettings().GetStyleSettings().GetHighContrastMode() )
+ {
+ Push( PUSH_LINECOLOR | PUSH_MAPMODE );
+ SetLineColor( Color( COL_WHITE ) );
+ SetMapMode( MapMode( MAP_PIXEL ) );
+ Size aSize = GetSizePixel();
+ DrawLine( Point( 0, aSize.Height()-1 ), Point( aSize.Width()-1, aSize.Height()-1 ) );
+ Pop();
+ }
+
+}
+
+void MenuBarWindow::Resize()
+{
+ Size aOutSz = GetOutputSizePixel();
+ long n = aOutSz.Height()-4;
+ long nX = aOutSz.Width()-3;
+ long nY = 2;
+
+ if ( aCloser.IsVisible() )
+ {
+ aCloser.Hide();
+ aCloser.SetImages( n );
+ Size aTbxSize( aCloser.CalcWindowSizePixel() );
+ nX -= aTbxSize.Width();
+ long nTbxY = (aOutSz.Height() - aTbxSize.Height())/2;
+ aCloser.SetPosSizePixel( nX, nTbxY, aTbxSize.Width(), aTbxSize.Height() );
+ nX -= 3;
+ aCloser.Show();
+ }
+ if ( aFloatBtn.IsVisible() )
+ {
+ nX -= n;
+ aFloatBtn.SetPosSizePixel( nX, nY, n, n );
+ }
+ if ( aHideBtn.IsVisible() )
+ {
+ nX -= n;
+ aHideBtn.SetPosSizePixel( nX, nY, n, n );
+ }
+
+ aFloatBtn.SetSymbol( SYMBOL_FLOAT );
+ aHideBtn.SetSymbol( SYMBOL_HIDE );
+ //aCloser.SetSymbol( SYMBOL_CLOSE ); //is a toolbox now
+
+ Invalidate();
+}
+
+USHORT MenuBarWindow::ImplFindEntry( const Point& rMousePos ) const
+{
+ if( pMenu )
+ {
+ long nX = 0;
+ USHORT nCount = (USHORT)pMenu->pItemList->Count();
+ for ( USHORT n = 0; n < nCount; n++ )
+ {
+ MenuItemData* pData = pMenu->pItemList->GetDataFromPos( n );
+ if ( pMenu->ImplIsVisible( n ) )
+ {
+ nX += pData->aSz.Width();
+ if ( nX > rMousePos.X() )
+ return (USHORT)n;
+ }
+ }
+ }
+ return ITEMPOS_INVALID;
+}
+
+void MenuBarWindow::RequestHelp( const HelpEvent& rHEvt )
+{
+ USHORT nId = nHighlightedItem;
+ if ( rHEvt.GetMode() & (HELPMODE_CONTEXT | HELPMODE_EXTENDED) )
+ ChangeHighlightItem( ITEMPOS_INVALID, TRUE );
+
+ Rectangle aHighlightRect( ImplGetItemRect( nHighlightedItem ) );
+ if( !ImplHandleHelpEvent( this, pMenu, nId, rHEvt, aHighlightRect ) )
+ Window::RequestHelp( rHEvt );
+}
+
+void MenuBarWindow::StateChanged( StateChangedType nType )
+{
+ Window::StateChanged( nType );
+
+ if ( ( nType == STATE_CHANGE_CONTROLFOREGROUND ) ||
+ ( nType == STATE_CHANGE_CONTROLBACKGROUND ) )
+ {
+ ImplInitMenuWindow( this, FALSE, TRUE );
+ Invalidate();
+ }
+ else if( pMenu )
+ pMenu->ImplKillLayoutData();
+
+}
+
+void MenuBarWindow::ImplLayoutChanged()
+{
+ if( pMenu )
+ {
+ ImplInitMenuWindow( this, TRUE, TRUE );
+ // Falls sich der Font geaendert hat.
+ long nHeight = pMenu->ImplCalcSize( this ).Height();
+
+ // depending on the native implementation or the displayable flag
+ // the menubar windows is supressed (ie, height=0)
+ if( !((MenuBar*) pMenu)->IsDisplayable() ||
+ ( pMenu->ImplGetSalMenu() && pMenu->ImplGetSalMenu()->VisibleMenuBar() ) )
+ nHeight = 0;
+
+ SetPosSizePixel( 0, 0, 0, nHeight, WINDOW_POSSIZE_HEIGHT );
+ GetParent()->Resize();
+ Invalidate();
+ Resize();
+ if( pMenu )
+ pMenu->ImplKillLayoutData();
+ }
+}
+
+void MenuBarWindow::ImplInitStyleSettings()
+{
+ if( IsNativeControlSupported( CTRL_MENUBAR, PART_MENU_ITEM ) &&
+ IsNativeControlSupported( CTRL_MENUBAR, PART_ENTIRE_CONTROL ) )
+ {
+ Color aHighlightTextColor = ImplGetSVData()->maNWFData.maMenuBarHighlightTextColor;
+ if( aHighlightTextColor != Color( COL_TRANSPARENT ) )
+ {
+ AllSettings aSettings( GetSettings() );
+ StyleSettings aStyle( aSettings.GetStyleSettings() );
+ aStyle.SetMenuHighlightTextColor( aHighlightTextColor );
+ aSettings.SetStyleSettings( aStyle );
+ OutputDevice::SetSettings( aSettings );
+ }
+ }
+}
+
+void MenuBarWindow::DataChanged( const DataChangedEvent& rDCEvt )
+{
+ Window::DataChanged( rDCEvt );
+
+ if ( (rDCEvt.GetType() == DATACHANGED_FONTS) ||
+ (rDCEvt.GetType() == DATACHANGED_FONTSUBSTITUTION) ||
+ ((rDCEvt.GetType() == DATACHANGED_SETTINGS) &&
+ (rDCEvt.GetFlags() & SETTINGS_STYLE)) )
+ {
+ ImplLayoutChanged();
+ ImplInitStyleSettings();
+ }
+}
+
+void MenuBarWindow::LoseFocus()
+{
+ if ( !HasChildPathFocus( TRUE ) )
+ ChangeHighlightItem( ITEMPOS_INVALID, FALSE, FALSE );
+}
+
+void MenuBarWindow::GetFocus()
+{
+ if ( nHighlightedItem == ITEMPOS_INVALID )
+ {
+ mbAutoPopup = FALSE; // do not open menu when activated by focus handling like taskpane cycling
+ ChangeHighlightItem( 0, FALSE );
+ }
+}
+
+::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible > MenuBarWindow::CreateAccessible()
+{
+ ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible > xAcc;
+
+ if ( pMenu )
+ xAcc = pMenu->GetAccessible();
+
+ return xAcc;
+}
+
+USHORT MenuBarWindow::AddMenuBarButton( const Image& i_rImage, const Link& i_rLink, const String& i_rToolTip, USHORT i_nPos )
+{
+ // find first free button id
+ USHORT nId = IID_DOCUMENTCLOSE;
+ std::map< USHORT, AddButtonEntry >::const_iterator it;
+ if( i_nPos > m_aAddButtons.size() )
+ i_nPos = static_cast<USHORT>(m_aAddButtons.size());
+ do
+ {
+ nId++;
+ it = m_aAddButtons.find( nId );
+ } while( it != m_aAddButtons.end() && nId < 128 );
+ DBG_ASSERT( nId < 128, "too many addbuttons in menubar" );
+ AddButtonEntry& rNewEntry = m_aAddButtons[nId];
+ rNewEntry.m_nId = nId;
+ rNewEntry.m_aSelectLink = i_rLink;
+ aCloser.InsertItem( nId, i_rImage, 0, 0 );
+ aCloser.calcMinSize();
+ ShowButtons( aCloser.IsItemVisible( IID_DOCUMENTCLOSE ),
+ aFloatBtn.IsVisible(),
+ aHideBtn.IsVisible() );
+ ImplLayoutChanged();
+
+ if( pMenu->mpSalMenu )
+ pMenu->mpSalMenu->AddMenuBarButton( SalMenuButtonItem( nId, i_rImage, i_rToolTip ) );
+
+ return nId;
+}
+
+void MenuBarWindow::SetMenuBarButtonHighlightHdl( USHORT nId, const Link& rLink )
+{
+ std::map< USHORT, AddButtonEntry >::iterator it = m_aAddButtons.find( nId );
+ if( it != m_aAddButtons.end() )
+ it->second.m_aHighlightLink = rLink;
+}
+
+Rectangle MenuBarWindow::GetMenuBarButtonRectPixel( USHORT nId )
+{
+ Rectangle aRect;
+ if( m_aAddButtons.find( nId ) != m_aAddButtons.end() )
+ {
+ if( pMenu->mpSalMenu )
+ {
+ aRect = pMenu->mpSalMenu->GetMenuBarButtonRectPixel( nId, ImplGetWindowImpl()->mpFrame );
+ if( aRect == Rectangle( Point( -1, -1 ), Size( 1, 1 ) ) )
+ {
+ // system menu button is somehwere but location cannot be determined
+ return Rectangle();
+ }
+ }
+
+ if( aRect.IsEmpty() )
+ {
+ aRect = aCloser.GetItemRect( nId );
+ Point aOffset = aCloser.OutputToScreenPixel( Point() );
+ aRect.Move( aOffset.X(), aOffset.Y() );
+ }
+ }
+ return aRect;
+}
+
+void MenuBarWindow::RemoveMenuBarButton( USHORT nId )
+{
+ USHORT nPos = aCloser.GetItemPos( nId );
+ aCloser.RemoveItem( nPos );
+ m_aAddButtons.erase( nId );
+ aCloser.calcMinSize();
+ ImplLayoutChanged();
+
+ if( pMenu->mpSalMenu )
+ pMenu->mpSalMenu->RemoveMenuBarButton( nId );
+}
+
+bool MenuBarWindow::HandleMenuButtonEvent( USHORT i_nButtonId )
+{
+ std::map< USHORT, AddButtonEntry >::iterator it = m_aAddButtons.find( i_nButtonId );
+ if( it != m_aAddButtons.end() )
+ {
+ MenuBar::MenuBarButtonCallbackArg aArg;
+ aArg.nId = it->first;
+ aArg.bHighlight = true;
+ aArg.pMenuBar = dynamic_cast<MenuBar*>(pMenu);
+ return it->second.m_aSelectLink.Call( &aArg );
+ }
+ return FALSE;
+}
+
+ImplMenuDelData::ImplMenuDelData( const Menu* pMenu )
+: mpNext( 0 )
+, mpMenu( 0 )
+{
+ if( pMenu )
+ const_cast< Menu* >( pMenu )->ImplAddDel( *this );
+}
+
+ImplMenuDelData::~ImplMenuDelData()
+{
+ if( mpMenu )
+ const_cast< Menu* >( mpMenu )->ImplRemoveDel( *this );
+}