| /************************************************************** |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| * |
| *************************************************************/ |
| |
| |
| |
| // MARKER(update_precomp.py): autogen include statement, do not remove |
| #include "precompiled_vcl.hxx" |
| |
| #include "tools/list.hxx" |
| #include "tools/debug.hxx" |
| #include "tools/diagnose_ex.h" |
| #include "tools/rc.h" |
| #include "tools/stream.hxx" |
| |
| #include "vcl/svapp.hxx" |
| #include "vcl/mnemonic.hxx" |
| #include "vcl/image.hxx" |
| #include "vcl/event.hxx" |
| #include "vcl/help.hxx" |
| #include "vcl/floatwin.hxx" |
| #include "vcl/wrkwin.hxx" |
| #include "vcl/timer.hxx" |
| #include "vcl/sound.hxx" |
| #include "vcl/decoview.hxx" |
| #include "vcl/bitmap.hxx" |
| #include "vcl/menu.hxx" |
| #include "vcl/button.hxx" |
| #include "vcl/gradient.hxx" |
| #include "vcl/i18nhelp.hxx" |
| #include "vcl/taskpanelist.hxx" |
| #include "vcl/controllayout.hxx" |
| #include "vcl/toolbox.hxx" |
| #include "vcl/dockingarea.hxx" |
| |
| #include "salinst.hxx" |
| #include "svdata.hxx" |
| #include "svids.hrc" |
| #include "window.h" |
| #include "salmenu.hxx" |
| #include "salframe.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< sal_uInt16 > m_aLineItemIds; |
| std::vector< sal_uInt16 > m_aLineItemPositions; |
| std::map< sal_uInt16, Rectangle > m_aVisibleItemBoundRects; |
| }; |
| |
| } |
| |
| using namespace ::com::sun::star; |
| using namespace vcl; |
| |
| DBG_NAME( Menu ) |
| |
| #define ITEMPOS_INVALID 0xFFFF |
| |
| #define EXTRASPACEY 2 |
| #define EXTRAITEMHEIGHT 4 |
| #define GUTTERBORDER 8 |
| |
| // document closer |
| #define IID_DOCUMENTCLOSE 1 |
| |
| #ifdef OS2 |
| |
| #include "svsys.h" |
| #include "os2/salmenu.h" |
| |
| // return sal_True if hilite should be executed: left mouse button down |
| // or xwp mouse hook enabled |
| static sal_Bool ImplHilite( const MouseEvent& rMEvt ) |
| { |
| static sal_Bool init = sal_False; |
| static HOOKCONFIG hc; |
| |
| // read XWP settings at program startup |
| if (init == sal_False) { |
| sal_Bool rc; |
| sal_uLong cb = sizeof(HOOKCONFIG); |
| memset(&hc, 0, sizeof(HOOKCONFIG)); |
| rc = PrfQueryProfileData( HINI_USER, INIAPP_XWPHOOK, INIKEY_HOOK_CONFIG, |
| &hc, &cb); |
| init = sal_True; |
| } |
| // check mouse left button |
| if (rMEvt.GetButtons() == MOUSE_LEFT) |
| return sal_True; |
| // return xwp flag |
| return hc.fSlidingMenus; |
| } |
| |
| #endif |
| |
| static sal_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) ? sal_True : sal_False; |
| } |
| |
| struct MenuItemData |
| { |
| sal_uInt16 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) |
| rtl::OString aHelpId; // Help-Id |
| sal_uLong nUserValue; // User value |
| Image aImage; // Image |
| KeyCode aAccelKey; // Accelerator-Key |
| sal_Bool bChecked; // Checked |
| sal_Bool bEnabled; // Enabled |
| sal_Bool bVisible; // Visible (note: this flag will not override MENU_FLAG_HIDEDISABLEDENTRIES when true) |
| sal_Bool bIsTemporary; // Temporary inserted ('No selection possible') |
| sal_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( sal_uInt16 nId, MenuItemType eType, MenuItemBits nBits, |
| const XubString& rStr, const Image& rImage, |
| Menu* pMenu, sal_uInt16 nPos ); |
| void InsertSeparator( sal_uInt16 nPos ); |
| void Remove( sal_uInt16 nPos ); |
| |
| |
| MenuItemData* GetData( sal_uInt16 nSVId, sal_uInt16& rPos ) const; |
| MenuItemData* GetData( sal_uInt16 nSVId ) const |
| { sal_uInt16 nTemp; return GetData( nSVId, nTemp ); } |
| MenuItemData* GetDataFromPos( sal_uLong nPos ) const |
| { return (MenuItemData*)List::GetObject( nPos ); } |
| |
| MenuItemData* SearchItem( xub_Unicode cSelectChar, KeyCode aKeyCode, sal_uInt16& rPos, sal_uInt16& nDuplicates, sal_uInt16 nCurrentPos ) const; |
| sal_uInt16 GetItemCount( xub_Unicode cSelectChar ) const; |
| sal_uInt16 GetItemCount( KeyCode aKeyCode ) const; |
| |
| uno::Reference< i18n::XCharacterClassification > GetCharClass() const; |
| }; |
| |
| |
| |
| MenuItemList::~MenuItemList() |
| { |
| for ( sal_uLong n = Count(); n; ) |
| { |
| MenuItemData* pData = GetDataFromPos( --n ); |
| delete pData; |
| } |
| } |
| |
| MenuItemData* MenuItemList::Insert( sal_uInt16 nId, MenuItemType eType, |
| MenuItemBits nBits, |
| const XubString& rStr, const Image& rImage, |
| Menu* pMenu, sal_uInt16 nPos ) |
| { |
| MenuItemData* pData = new MenuItemData( rStr, rImage ); |
| pData->nId = nId; |
| pData->eType = eType; |
| pData->nBits = nBits; |
| pData->pSubMenu = NULL; |
| pData->pAutoSubMenu = NULL; |
| pData->nUserValue = 0; |
| pData->bChecked = sal_False; |
| pData->bEnabled = sal_True; |
| pData->bVisible = sal_True; |
| pData->bIsTemporary = sal_False; |
| pData->bMirrorMode = sal_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( sal_uInt16 nPos ) |
| { |
| MenuItemData* pData = new MenuItemData; |
| pData->nId = 0; |
| pData->eType = MENUITEM_SEPARATOR; |
| pData->nBits = 0; |
| pData->pSubMenu = NULL; |
| pData->pAutoSubMenu = NULL; |
| pData->nUserValue = 0; |
| pData->bChecked = sal_False; |
| pData->bEnabled = sal_True; |
| pData->bVisible = sal_True; |
| pData->bIsTemporary = sal_False; |
| pData->bMirrorMode = sal_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( sal_uInt16 nPos ) |
| { |
| MenuItemData* pData = (MenuItemData*)List::Remove( (sal_uLong)nPos ); |
| if ( pData ) |
| delete pData; |
| } |
| |
| MenuItemData* MenuItemList::GetData( sal_uInt16 nSVId, sal_uInt16& 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, sal_uInt16& rPos, sal_uInt16& nDuplicates, sal_uInt16 nCurrentPos ) const |
| { |
| const vcl::I18nHelper& rI18nHelper = Application::GetSettings().GetUILocaleI18nHelper(); |
| |
| sal_uInt16 nListCount = (sal_uInt16)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 ) |
| { |
| sal_uInt16 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; |
| } |
| |
| sal_uInt16 MenuItemList::GetItemCount( xub_Unicode cSelectChar ) const |
| { |
| // returns number of entries with same mnemonic |
| const vcl::I18nHelper& rI18nHelper = Application::GetSettings().GetUILocaleI18nHelper(); |
| |
| sal_uInt16 nItems = 0, nPos; |
| for ( nPos = (sal_uInt16)Count(); nPos; ) |
| { |
| MenuItemData* pData = GetDataFromPos( --nPos ); |
| if ( pData->bEnabled && rI18nHelper.MatchMnemonic( pData->aText, cSelectChar ) ) |
| nItems++; |
| } |
| |
| return nItems; |
| } |
| |
| sal_uInt16 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)); |
| |
| sal_uInt16 nItems = 0, nPos; |
| for ( nPos = (sal_uInt16)Count(); nPos; ) |
| { |
| MenuItemData* pData = GetDataFromPos( --nPos ); |
| if ( pData->bEnabled ) |
| { |
| sal_uInt16 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; |
| sal_uLong nSaveFocusId; |
| // long nStartY; |
| sal_uInt16 nHighlightedItem; // gehighlightetes/selektiertes Item |
| sal_uInt16 nMBDownPos; |
| sal_uInt16 nScrollerHeight; |
| sal_uInt16 nFirstEntry; |
| sal_uInt16 nBorder; |
| sal_uInt16 nPosInParent; |
| sal_Bool bInExecute; |
| |
| sal_Bool bScrollMenu; |
| sal_Bool bScrollUp; |
| sal_Bool bScrollDown; |
| sal_Bool bIgnoreFirstMove; |
| sal_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( sal_Bool bIncludeLogo = sal_True ) const; |
| void ImplInitClipRegion(); |
| void ImplDrawScroller( sal_Bool bUp ); |
| using Window::ImplScroll; |
| void ImplScroll( const Point& rMousePos ); |
| void ImplScroll( sal_Bool bUp ); |
| void ImplCursorUpDown( sal_Bool bUp, sal_Bool bHomeEnd = sal_False ); |
| void ImplHighlightItem( const MouseEvent& rMEvt, sal_Bool bMBDown ); |
| long ImplGetStartY() const; |
| Rectangle ImplGetItemRect( sal_uInt16 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( sal_uLong nId ) { nSaveFocusId = nId; } |
| sal_uLong GetFocusId() const { return nSaveFocusId; } |
| |
| void EnableScrollMenu( sal_Bool b ); |
| sal_Bool IsScrollMenu() const { return bScrollMenu; } |
| sal_uInt16 GetScrollerHeight() const { return nScrollerHeight; } |
| |
| void Execute(); |
| void StopExecute( sal_uLong nFocusId = 0 ); |
| void EndExecute(); |
| void EndExecute( sal_uInt16 nSelectId ); |
| |
| PopupMenu* GetActivePopup() const { return pActivePopup; } |
| void KillActivePopup( PopupMenu* pThisOnly = NULL ); |
| |
| void HighlightItem( sal_uInt16 nPos, sal_Bool bHighlight ); |
| void ChangeHighlightItem( sal_uInt16 n, sal_Bool bStartPopupTimer ); |
| sal_uInt16 GetHighlightedItem() const { return nHighlightedItem; } |
| |
| void SetPosInParent( sal_uInt16 nPos ) { nPosInParent = nPos; } |
| sal_uInt16 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 |
| { |
| sal_uInt16 nItems = GetItemCount(); |
| for( sal_uInt16 i = 0; i < nItems; i++ ) |
| { |
| sal_uInt16 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 |
| { |
| sal_uInt16 m_nId; |
| Link m_aSelectLink; |
| Link m_aHighlightLink; |
| |
| AddButtonEntry() : m_nId( 0 ) {} |
| }; |
| |
| Menu* pMenu; |
| PopupMenu* pActivePopup; |
| sal_uInt16 nHighlightedItem; |
| sal_uLong nSaveFocusId; |
| sal_Bool mbAutoPopup; |
| sal_Bool bIgnoreFirstMove; |
| sal_Bool bStayActive; |
| |
| DecoToolBox aCloser; |
| PushButton aFloatBtn; |
| PushButton aHideBtn; |
| |
| std::map< sal_uInt16, AddButtonEntry > m_aAddButtons; |
| |
| void HighlightItem( sal_uInt16 nPos, sal_Bool bHighlight ); |
| void ChangeHighlightItem( sal_uInt16 n, sal_Bool bSelectPopupEntry, sal_Bool bAllowRestoreFocus = sal_True, sal_Bool bDefaultToDocument = sal_True ); |
| |
| sal_uInt16 ImplFindEntry( const Point& rMousePos ) const; |
| void ImplCreatePopup( sal_Bool bPreSelectFirst ); |
| sal_Bool ImplHandleKeyEvent( const KeyEvent& rKEvent, sal_Bool bFromMenu = sal_True ); |
| Rectangle ImplGetItemRect( sal_uInt16 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( sal_Bool bClose, sal_Bool bFloat, sal_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( sal_uLong nId ) { nSaveFocusId = nId; } |
| sal_uLong GetFocusId() const { return nSaveFocusId; } |
| |
| void SetMenu( MenuBar* pMenu ); |
| void KillActivePopup(); |
| PopupMenu* GetActivePopup() const { return pActivePopup; } |
| void PopupClosed( Menu* pMenu ); |
| sal_uInt16 GetHighlightedItem() const { return nHighlightedItem; } |
| virtual ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible > CreateAccessible(); |
| |
| void SetAutoPopup( sal_Bool bAuto ) { mbAutoPopup = bAuto; } |
| void ImplLayoutChanged(); |
| Size MinCloseButtonSize(); |
| |
| // add an arbitrary button to the menubar (will appear next to closer) |
| sal_uInt16 AddMenuBarButton( const Image&, const Link&, const String&, sal_uInt16 nPos ); |
| void SetMenuBarButtonHighlightHdl( sal_uInt16 nId, const Link& ); |
| Rectangle GetMenuBarButtonRectPixel( sal_uInt16 nId ); |
| void RemoveMenuBarButton( sal_uInt16 nId ); |
| bool HandleMenuButtonEvent( sal_uInt16 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 sal_uLong ImplChangeTipTimeout( sal_uLong nTimeout, Window *pWindow ) |
| { |
| AllSettings aAllSettings( pWindow->GetSettings() ); |
| HelpSettings aHelpSettings( aAllSettings.GetHelpSettings() ); |
| sal_uLong nRet = aHelpSettings.GetTipTimeout(); |
| aHelpSettings.SetTipTimeout( nTimeout ); |
| aAllSettings.SetHelpSettings( aHelpSettings ); |
| pWindow->SetSettings( aAllSettings ); |
| return nRet; |
| } |
| |
| static sal_Bool ImplHandleHelpEvent( Window* pMenuWindow, Menu* pMenu, sal_uInt16 nHighlightedItem, const HelpEvent& rHEvt, const Rectangle &rHighlightRect ) |
| { |
| if( ! pMenu ) |
| return sal_False; |
| |
| sal_Bool bDone = sal_False; |
| sal_uInt16 nId = 0; |
| |
| if ( nHighlightedItem != ITEMPOS_INVALID ) |
| { |
| MenuItemData* pItemData = pMenu->GetItemList()->GetDataFromPos( nHighlightedItem ); |
| if ( pItemData ) |
| nId = pItemData->nId; |
| } |
| |
| if ( ( rHEvt.GetMode() & HELPMODE_BALLOON ) && pMenuWindow ) |
| { |
| Point aPos; |
| if( rHEvt.KeyboardActivated() ) |
| aPos = rHighlightRect.Center(); |
| else |
| aPos = rHEvt.GetMousePosPixel(); |
| |
| Rectangle aRect( aPos, Size() ); |
| if( pMenu->GetHelpText( nId ).Len() ) |
| Help::ShowBalloon( pMenuWindow, aPos, pMenu->GetHelpText( nId ) ); |
| else |
| { |
| // give user a chance to read the full filename |
| sal_uLong oldTimeout=ImplChangeTipTimeout( 60000, pMenuWindow ); |
| // call always, even when strlen==0 to correctly remove tip |
| Help::ShowQuickHelp( pMenuWindow, aRect, pMenu->GetTipHelpText( nId ) ); |
| ImplChangeTipTimeout( oldTimeout, pMenuWindow ); |
| } |
| bDone = sal_True; |
| } |
| else if ( ( rHEvt.GetMode() & HELPMODE_QUICK ) && pMenuWindow ) |
| { |
| Point aPos = rHEvt.GetMousePosPixel(); |
| Rectangle aRect( aPos, Size() ); |
| // give user a chance to read the full filename |
| sal_uLong oldTimeout=ImplChangeTipTimeout( 60000, pMenuWindow ); |
| // call always, even when strlen==0 to correctly remove tip |
| Help::ShowQuickHelp( pMenuWindow, aRect, pMenu->GetTipHelpText( nId ) ); |
| ImplChangeTipTimeout( oldTimeout, pMenuWindow ); |
| bDone = sal_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 ); |
| rtl::OString aHelpId( pMenu->GetHelpId( nId ) ); |
| if( ! aHelpId.getLength() ) |
| aHelpId = OOO_HELP_INDEX; |
| |
| if ( aCommand.Len() ) |
| pHelp->Start( aCommand, NULL ); |
| else |
| pHelp->Start( rtl::OStringToOUString( aHelpId, RTL_TEXTENCODING_UTF8 ), NULL ); |
| } |
| bDone = sal_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; |
| sal_Bool bDone = sal_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 = sal_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 = sal_False; |
| ImplInit(); |
| } |
| |
| // this constructor makes sure we're creating the native menu |
| // with the correct type (ie, MenuBar vs. PopupMenu) |
| Menu::Menu( sal_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 = sal_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 = sal_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 = sal_False; |
| bInCallback = sal_False; |
| bKilled = sal_False; |
| mpLayoutData = NULL; |
| mpFirstDel = NULL; // Dtor notification list |
| // Native-support: returns NULL if not supported |
| mpSalMenu = ImplGetSVData()->mpDefInst->CreateMenu( bIsMenuBar, this ); |
| } |
| |
| 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 ); |
| |
| sal_uLong nObjMask = ReadLongRes(); |
| |
| if( nObjMask & RSC_MENU_ITEMS ) |
| { |
| sal_uLong nObjFollows = ReadLongRes(); |
| // MenuItems einfuegen |
| for( sal_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<sal_uInt16>(ReadLongRes()) ); |
| } |
| |
| void Menu::CreateAutoMnemonics() |
| { |
| MnemonicGenerator aMnemonicGenerator; |
| sal_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 = sal_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 = sal_True; |
| // MT 11/01: Call EventListener here? I don't know... |
| pStartMenu->aActivateHdl.Call( this ); |
| pStartMenu->bInCallback = sal_False; |
| } |
| } |
| } |
| bInCallback = sal_False; |
| } |
| } |
| |
| void Menu::Deactivate() |
| { |
| for ( sal_uInt16 n = (sal_uInt16)pItemList->Count(); n; ) |
| { |
| MenuItemData* pData = pItemList->GetDataFromPos( --n ); |
| if ( pData->bIsTemporary ) |
| pItemList->Remove( n ); |
| } |
| |
| bInCallback = sal_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 = sal_True; |
| pStartMenu->aDeactivateHdl.Call( this ); |
| pStartMenu->bInCallback = sal_False; |
| } |
| } |
| } |
| } |
| |
| if( !aDelData.isDeleted() ) |
| { |
| bInCallback = sal_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) ) |
| { |
| sal_Bool bChecked = IsItemChecked( nSelectedId ); |
| if ( pData->nBits & MIB_RADIOCHECK ) |
| { |
| if ( !bChecked ) |
| CheckItem( nSelectedId, sal_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( sal_uLong nEvent, sal_uInt16 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( sal_uInt16 nItemId, const XubString& rStr, MenuItemBits nItemBits, sal_uInt16 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 >= (sal_uInt16)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( sal_uInt16 nItemId, const Image& rImage, |
| MenuItemBits nItemBits, sal_uInt16 nPos ) |
| { |
| InsertItem( nItemId, ImplGetSVEmptyStr(), nItemBits, nPos ); |
| SetItemImage( nItemId, rImage ); |
| } |
| |
| void Menu::InsertItem( sal_uInt16 nItemId, |
| const XubString& rStr, const Image& rImage, |
| MenuItemBits nItemBits, sal_uInt16 nPos ) |
| { |
| InsertItem( nItemId, rStr, nItemBits, nPos ); |
| SetItemImage( nItemId, rImage ); |
| } |
| |
| void Menu::InsertItem( const ResId& rResId, sal_uInt16 nPos ) |
| { |
| ResMgr* pMgr = rResId.GetResMgr(); |
| if( ! pMgr ) |
| return; |
| |
| sal_uLong nObjMask; |
| |
| GetRes( rResId.SetRT( RSC_MENUITEM ) ); |
| nObjMask = ReadLongRes(); |
| |
| sal_Bool bSep = sal_False; |
| if ( nObjMask & RSC_MENUITEM_SEPARATOR ) |
| bSep = (sal_Bool)ReadShortRes(); |
| |
| sal_uInt16 nItemId = 1; |
| if ( nObjMask & RSC_MENUITEM_ID ) |
| nItemId = sal::static_int_cast<sal_uInt16>(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 ); |
| } |
| |
| if ( nObjMask & RSC_MENUITEM_HELPID ) |
| { |
| rtl::OString aHelpId( ReadByteStringRes() ); |
| if ( !bSep ) |
| SetHelpId( nItemId, aHelpId ); |
| } |
| |
| if( !bSep ) |
| 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, (sal_Bool)ReadShortRes() ); |
| } |
| if ( nObjMask & RSC_MENUITEM_DISABLE ) |
| { |
| if ( !bSep ) |
| EnableItem( nItemId, !(sal_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( sal_uInt16 nPos ) |
| { |
| // do nothing if its a menu bar |
| if ( bIsMenuBar ) |
| return; |
| |
| // if position > ItemCount, append |
| if ( nPos >= (sal_uInt16)pItemList->Count() ) |
| nPos = MENU_APPEND; |
| |
| // put separator in item list |
| pItemList->InsertSeparator( nPos ); |
| |
| // update native menu |
| sal_uInt16 itemPos = nPos != MENU_APPEND ? nPos : (sal_uInt16)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( sal_uInt16 nPos ) |
| { |
| sal_Bool bRemove = sal_False; |
| |
| if ( nPos < GetItemCount() ) |
| { |
| // update native menu |
| if( ImplGetSalMenu() ) |
| ImplGetSalMenu()->RemoveItem( nPos ); |
| |
| pItemList->Remove( nPos ); |
| bRemove = sal_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, sal_uInt16 nPos, sal_uInt16 nNewPos, |
| sal_uInt16 nMode = 0 ) |
| { |
| MenuItemType eType = rMenu.GetItemType( nPos ); |
| |
| if ( eType == MENUITEM_DONTKNOW ) |
| return; |
| |
| if ( eType == MENUITEM_SEPARATOR ) |
| pThis->InsertSeparator( nNewPos ); |
| else |
| { |
| sal_uInt16 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, sal_True ); |
| if ( !rMenu.IsItemEnabled( nId ) ) |
| pThis->EnableItem( nId, sal_False ); |
| pThis->SetHelpId( nId, pData->aHelpId ); |
| 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, sal_uInt16 nPos, sal_uInt16 nNewPos ) |
| { |
| ImplCopyItem( this, rMenu, nPos, nNewPos ); |
| } |
| |
| void Menu::Clear() |
| { |
| for ( sal_uInt16 i = GetItemCount(); i; i-- ) |
| RemoveItem( 0 ); |
| } |
| |
| sal_uInt16 Menu::GetItemCount() const |
| { |
| return (sal_uInt16)pItemList->Count(); |
| } |
| |
| sal_uInt16 Menu::ImplGetVisibleItemCount() const |
| { |
| sal_uInt16 nItems = 0; |
| for ( sal_uInt16 n = (sal_uInt16)pItemList->Count(); n; ) |
| { |
| if ( ImplIsVisible( --n ) ) |
| nItems++; |
| } |
| return nItems; |
| } |
| |
| sal_uInt16 Menu::ImplGetFirstVisible() const |
| { |
| for ( sal_uInt16 n = 0; n < pItemList->Count(); n++ ) |
| { |
| if ( ImplIsVisible( n ) ) |
| return n; |
| } |
| return ITEMPOS_INVALID; |
| } |
| |
| sal_uInt16 Menu::ImplGetPrevVisible( sal_uInt16 nPos ) const |
| { |
| for ( sal_uInt16 n = nPos; n; ) |
| { |
| if ( n && ImplIsVisible( --n ) ) |
| return n; |
| } |
| return ITEMPOS_INVALID; |
| } |
| |
| sal_uInt16 Menu::ImplGetNextVisible( sal_uInt16 nPos ) const |
| { |
| for ( sal_uInt16 n = nPos+1; n < pItemList->Count(); n++ ) |
| { |
| if ( ImplIsVisible( n ) ) |
| return n; |
| } |
| return ITEMPOS_INVALID; |
| } |
| |
| sal_uInt16 Menu::GetItemId( sal_uInt16 nPos ) const |
| { |
| MenuItemData* pData = pItemList->GetDataFromPos( nPos ); |
| |
| if ( pData ) |
| return pData->nId; |
| else |
| return 0; |
| } |
| |
| sal_uInt16 Menu::GetItemPos( sal_uInt16 nItemId ) const |
| { |
| sal_uInt16 nPos; |
| MenuItemData* pData = pItemList->GetData( nItemId, nPos ); |
| |
| if ( pData ) |
| return nPos; |
| else |
| return MENU_ITEM_NOTFOUND; |
| } |
| |
| MenuItemType Menu::GetItemType( sal_uInt16 nPos ) const |
| { |
| MenuItemData* pData = pItemList->GetDataFromPos( nPos ); |
| |
| if ( pData ) |
| return pData->eType; |
| else |
| return MENUITEM_DONTKNOW; |
| } |
| |
| sal_uInt16 Menu::GetCurItemId() const |
| { |
| return nSelectedId; |
| } |
| void Menu::SetHightlightItem( sal_uInt16 nHighlightedItem ) |
| { |
| this->nHighlightedItem = nHighlightedItem; |
| } |
| sal_uInt16 Menu::GetHighlightItem() const |
| { |
| return nHighlightedItem; |
| } |
| |
| |
| XubString Menu::GetItemAccKeyStrFromPos(sal_uInt16 nPos) const |
| { |
| MenuItemData* pData = pItemList->GetDataFromPos( nPos ); |
| if (pData) |
| { |
| return pData->aAccelKey.GetName(); |
| } |
| return XubString(); |
| } |
| |
| sal_Bool Menu::IsTemporaryItemFromPos(sal_uInt16 nPos ) const |
| { |
| MenuItemData* pData = pItemList->GetDataFromPos( nPos ); |
| if (pData) |
| { |
| return pData->bIsTemporary; |
| } |
| return sal_False; |
| } |
| |
| void Menu::SetItemBits( sal_uInt16 nItemId, MenuItemBits nBits ) |
| { |
| MenuItemData* pData = pItemList->GetData( nItemId ); |
| if ( pData ) |
| pData->nBits = nBits; |
| } |
| |
| MenuItemBits Menu::GetItemBits( sal_uInt16 nItemId ) const |
| { |
| MenuItemBits nBits = 0; |
| MenuItemData* pData = pItemList->GetData( nItemId ); |
| if ( pData ) |
| nBits = pData->nBits; |
| return nBits; |
| } |
| |
| void Menu::SetUserValue( sal_uInt16 nItemId, sal_uLong nValue ) |
| { |
| MenuItemData* pData = pItemList->GetData( nItemId ); |
| if ( pData ) |
| pData->nUserValue = nValue; |
| } |
| |
| sal_uLong Menu::GetUserValue( sal_uInt16 nItemId ) const |
| { |
| MenuItemData* pData = pItemList->GetData( nItemId ); |
| return pData ? pData->nUserValue : 0; |
| } |
| |
| void Menu::SetPopupMenu( sal_uInt16 nItemId, PopupMenu* pMenu ) |
| { |
| sal_uInt16 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( sal_uInt16 nItemId ) const |
| { |
| MenuItemData* pData = pItemList->GetData( nItemId ); |
| |
| if ( pData ) |
| return (PopupMenu*)(pData->pSubMenu); |
| else |
| return NULL; |
| } |
| |
| void Menu::SetAccelKey( sal_uInt16 nItemId, const KeyCode& rKeyCode ) |
| { |
| sal_uInt16 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( sal_uInt16 nItemId ) const |
| { |
| MenuItemData* pData = pItemList->GetData( nItemId ); |
| |
| if ( pData ) |
| return pData->aAccelKey; |
| else |
| return KeyCode(); |
| } |
| |
| KeyEvent Menu::GetActivationKey( sal_uInt16 nItemId ) const |
| { |
| KeyEvent aRet; |
| MenuItemData* pData = pItemList->GetData( nItemId ); |
| if( pData ) |
| { |
| sal_uInt16 nPos = pData->aText.Search( '~' ); |
| if( nPos != STRING_NOTFOUND && nPos < pData->aText.Len()-1 ) |
| { |
| sal_uInt16 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( sal_uInt16 nItemId, sal_Bool bCheck ) |
| { |
| sal_uInt16 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; |
| sal_uInt16 nGroupPos; |
| sal_uInt16 nItemCount = GetItemCount(); |
| sal_Bool bFound = sal_False; |
| |
| nGroupPos = nPos; |
| while ( nGroupPos ) |
| { |
| pGroupData = pItemList->GetDataFromPos( nGroupPos-1 ); |
| if ( pGroupData->nBits & MIB_RADIOCHECK ) |
| { |
| if ( IsItemChecked( pGroupData->nId ) ) |
| { |
| CheckItem( pGroupData->nId, sal_False ); |
| bFound = sal_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, sal_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 ); |
| } |
| |
| sal_Bool Menu::IsItemChecked( sal_uInt16 nItemId ) const |
| { |
| sal_uInt16 nPos; |
| MenuItemData* pData = pItemList->GetData( nItemId, nPos ); |
| |
| if ( !pData ) |
| return sal_False; |
| |
| return pData->bChecked; |
| } |
| |
| void Menu::EnableItem( sal_uInt16 nItemId, sal_Bool bEnable ) |
| { |
| sal_uInt16 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; |
| sal_uLong nCount = pItemList->Count(); |
| for ( sal_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 ); |
| } |
| } |
| |
| sal_Bool Menu::IsItemEnabled( sal_uInt16 nItemId ) const |
| { |
| sal_uInt16 nPos; |
| MenuItemData* pData = pItemList->GetData( nItemId, nPos ); |
| |
| if ( !pData ) |
| return sal_False; |
| |
| return pData->bEnabled; |
| } |
| |
| void Menu::ShowItem( sal_uInt16 nItemId, sal_Bool bVisible ) |
| { |
| sal_uInt16 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( sal_uInt16 nItemId, const XubString& rStr ) |
| { |
| sal_uInt16 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( sal_uInt16 nItemId ) const |
| { |
| sal_uInt16 nPos; |
| MenuItemData* pData = pItemList->GetData( nItemId, nPos ); |
| |
| if ( pData ) |
| return pData->aText; |
| else |
| return ImplGetSVEmptyStr(); |
| } |
| |
| void Menu::SetItemImage( sal_uInt16 nItemId, const Image& rImage ) |
| { |
| sal_uInt16 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( sal_uInt16 nItemId, long nAngle10 ) |
| { |
| sal_uInt16 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( sal_uInt16 nItemId, sal_Bool bMirror ) |
| { |
| sal_uInt16 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( sal_uInt16 nItemId ) const |
| { |
| MenuItemData* pData = pItemList->GetData( nItemId ); |
| |
| if ( pData ) |
| return pData->aImage; |
| else |
| return Image(); |
| } |
| |
| long Menu::GetItemImageAngle( sal_uInt16 nItemId ) const |
| { |
| MenuItemData* pData = pItemList->GetData( nItemId ); |
| |
| if ( pData ) |
| return pData->nItemImageAngle; |
| else |
| return 0; |
| } |
| |
| sal_Bool Menu::GetItemImageMirrorMode( sal_uInt16 nItemId ) const |
| { |
| MenuItemData* pData = pItemList->GetData( nItemId ); |
| |
| if ( pData ) |
| return pData->bMirrorMode; |
| else |
| return sal_False; |
| } |
| |
| void Menu::SetItemCommand( sal_uInt16 nItemId, const String& rCommand ) |
| { |
| MenuItemData* pData = pItemList->GetData( nItemId ); |
| |
| if ( pData ) |
| pData->aCommandStr = rCommand; |
| } |
| |
| const XubString& Menu::GetItemCommand( sal_uInt16 nItemId ) const |
| { |
| MenuItemData* pData = pItemList->GetData( nItemId ); |
| |
| if ( pData ) |
| return pData->aCommandStr; |
| else |
| return ImplGetSVEmptyStr(); |
| } |
| |
| void Menu::SetHelpCommand( sal_uInt16 nItemId, const XubString& rStr ) |
| { |
| MenuItemData* pData = pItemList->GetData( nItemId ); |
| |
| if ( pData ) |
| pData->aHelpCommandStr = rStr; |
| } |
| |
| const XubString& Menu::GetHelpCommand( sal_uInt16 nItemId ) const |
| { |
| MenuItemData* pData = pItemList->GetData( nItemId ); |
| |
| if ( pData ) |
| return pData->aHelpCommandStr; |
| else |
| return ImplGetSVEmptyStr(); |
| } |
| |
| void Menu::SetHelpText( sal_uInt16 nItemId, const XubString& rStr ) |
| { |
| MenuItemData* pData = pItemList->GetData( nItemId ); |
| |
| if ( pData ) |
| pData->aHelpText = rStr; |
| } |
| |
| const XubString& Menu::ImplGetHelpText( sal_uInt16 nItemId ) const |
| { |
| MenuItemData* pData = pItemList->GetData( nItemId ); |
| |
| if ( pData ) |
| { |
| if ( !pData->aHelpText.Len() && |
| (( pData->aHelpId.getLength() ) || ( 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->aHelpId.getLength() ) |
| pData->aHelpText = pHelp->GetHelpText( rtl::OStringToOUString( pData->aHelpId, RTL_TEXTENCODING_UTF8 ), NULL ); |
| } |
| } |
| |
| return pData->aHelpText; |
| } |
| else |
| return ImplGetSVEmptyStr(); |
| } |
| |
| const XubString& Menu::GetHelpText( sal_uInt16 nItemId ) const |
| { |
| return ImplGetHelpText( nItemId ); |
| } |
| |
| void Menu::SetTipHelpText( sal_uInt16 nItemId, const XubString& rStr ) |
| { |
| MenuItemData* pData = pItemList->GetData( nItemId ); |
| |
| if ( pData ) |
| pData->aTipHelpText = rStr; |
| } |
| |
| const XubString& Menu::GetTipHelpText( sal_uInt16 nItemId ) const |
| { |
| MenuItemData* pData = pItemList->GetData( nItemId ); |
| |
| if ( pData ) |
| return pData->aTipHelpText; |
| else |
| return ImplGetSVEmptyStr(); |
| } |
| |
| void Menu::SetHelpId( sal_uInt16 nItemId, const rtl::OString& rHelpId ) |
| { |
| MenuItemData* pData = pItemList->GetData( nItemId ); |
| |
| if ( pData ) |
| pData->aHelpId = rHelpId; |
| } |
| |
| rtl::OString Menu::GetHelpId( sal_uInt16 nItemId ) const |
| { |
| rtl::OString aRet; |
| |
| MenuItemData* pData = pItemList->GetData( nItemId ); |
| |
| if ( pData ) |
| { |
| if ( pData->aHelpId.getLength() ) |
| aRet = pData->aHelpId; |
| else |
| aRet = ::rtl::OUStringToOString( pData->aCommandStr, RTL_TEXTENCODING_UTF8 ); |
| } |
| |
| return aRet; |
| } |
| |
| Menu& Menu::operator=( const Menu& rMenu ) |
| { |
| // Aufraeumen |
| Clear(); |
| |
| // Items kopieren |
| sal_uInt16 nCount = rMenu.GetItemCount(); |
| for ( sal_uInt16 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; |
| } |
| |
| sal_Bool Menu::ImplIsVisible( sal_uInt16 nPos ) const |
| { |
| sal_Bool bVisible = sal_True; |
| |
| MenuItemData* pData = pItemList->GetDataFromPos( nPos ); |
| // check general visibility first |
| if( pData && !pData->bVisible ) |
| bVisible = sal_False; |
| |
| if ( bVisible && pData && pData->eType == MENUITEM_SEPARATOR ) |
| { |
| if( nPos == 0 ) // no separator should be shown at the very beginning |
| bVisible = sal_False; |
| else |
| { |
| // always avoid adjacent separators |
| sal_uInt16 nCount = (sal_uInt16) pItemList->Count(); |
| sal_uInt16 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 = sal_False; |
| // check for separator |
| if( pNextData && pNextData->bVisible && pNextData->eType == MENUITEM_SEPARATOR ) |
| bVisible = sal_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 = sal_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 = sal_False; |
| else if ( pData->eType != MENUITEM_SEPARATOR ) // separators handled above |
| { |
| // bVisible = pData->bEnabled && ( !pData->pSubMenu || pData->pSubMenu->HasValidEntries( sal_True ) ); |
| bVisible = pData->bEnabled; // SubMenus nicht pruefen, weil sie ggf. erst im Activate() gefuellt werden. |
| } |
| } |
| |
| return bVisible; |
| } |
| |
| sal_Bool Menu::IsItemVisible( sal_uInt16 nItemId ) const |
| { |
| return IsMenuVisible() && ImplIsVisible( GetItemPos( nItemId ) ); |
| } |
| |
| sal_Bool Menu::IsItemPosVisible( sal_uInt16 nItemPos ) const |
| { |
| return IsMenuVisible() && ImplIsVisible( nItemPos ); |
| } |
| |
| sal_Bool Menu::IsMenuVisible() const |
| { |
| return pWindow && pWindow->IsReallyVisible(); |
| } |
| |
| sal_Bool Menu::ImplIsSelectable( sal_uInt16 nPos ) const |
| { |
| sal_Bool bSelectable = sal_True; |
| |
| MenuItemData* pData = pItemList->GetDataFromPos( nPos ); |
| // check general visibility first |
| if ( pData && ( pData->nBits & MIB_NOSELECT ) ) |
| bSelectable = sal_False; |
| |
| return bSelectable; |
| } |
| |
| void Menu::SelectItem( sal_uInt16 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 ( sal_uInt16 i = (sal_uInt16)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 ( sal_uInt16 n = (sal_uInt16)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 ) |
| { |
| // popup menus should not be wider than half the screen |
| // except on rather small screens |
| // TODO: move GetScreenNumber from SystemWindow to Window ? |
| // currently we rely on internal privileges |
| unsigned int nScreenNumber = pWin->ImplGetWindowImpl()->mpFrame->maGeometry.nScreenNumber; |
| Rectangle aDispRect( Application::GetScreenPosSizePixel( nScreenNumber ) ); |
| long nScreenWidth = aDispRect.GetWidth() >= 800 ? aDispRect.GetWidth() : 800; |
| if( nMaxWidth > nScreenWidth/2 ) |
| nMaxWidth = nScreenWidth/2; |
| |
| sal_uInt16 gfxExtra = (sal_uInt16) Max( nExtra, 7L ); // #107710# increase space between checkmarks/images/text |
| nCheckPos = (sal_uInt16)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 = (sal_uInt16)(nImagePos + nImgOrChkWidth); |
| } |
| else |
| { |
| nImagePos = nCheckPos; |
| nTextPos = (sal_uInt16)(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 = (sal_uInt16)(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 ) |
| { |
| sal_Bool bNativeOk = sal_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, sal_True, sal_False, 2, NULL, &aColor ); |
| } |
| } |
| |
| static String getShortenedString( const String& i_rLong, Window* i_pWin, long i_nMaxWidth ) |
| { |
| xub_StrLen nPos = STRING_NOTFOUND; |
| String aNonMnem( OutputDevice::GetNonMnemonicString( i_rLong, nPos ) ); |
| aNonMnem = i_pWin->GetEllipsisString( aNonMnem, i_nMaxWidth, TEXT_DRAW_CENTERELLIPSIS ); |
| // re-insert mnemonic |
| if( nPos != STRING_NOTFOUND ) |
| { |
| if( nPos < aNonMnem.Len() && i_rLong.GetChar(nPos+1) == aNonMnem.GetChar(nPos) ) |
| { |
| rtl::OUStringBuffer aBuf( i_rLong.Len() ); |
| aBuf.append( aNonMnem.GetBuffer(), nPos ); |
| aBuf.append( sal_Unicode('~') ); |
| aBuf.append( aNonMnem.GetBuffer()+nPos ); |
| aNonMnem = aBuf.makeStringAndClear(); |
| } |
| } |
| return aNonMnem; |
| } |
| |
| void Menu::ImplPaint( Window* pWin, sal_uInt16 nBorder, long nStartY, MenuItemData* pThisItemOnly, sal_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(); |
| sal_uInt16 nCount = (sal_uInt16)pItemList->Count(); |
| if( bLayout ) |
| mpLayoutData->m_aVisibleItemBoundRects.clear(); |
| for ( sal_uInt16 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; |
| sal_uInt16 nTextStyle = 0; |
| sal_uInt16 nSymbolStyle = 0; |
| sal_uInt16 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 ) ) |
| { |
| bool bNativeOk = false; |
| if( pWin->IsNativeControlSupported( CTRL_MENU_POPUP, |
| PART_MENU_SEPARATOR ) ) |
| { |
| ControlState nState = 0; |
| if ( pData->bEnabled ) |
| nState |= CTRL_STATE_ENABLED; |
| if ( bHighlighted ) |
| nState |= CTRL_STATE_SELECTED; |
| Size aSz( pData->aSz ); |
| aSz.Width() = aOutSz.Width() - 2*nOuterSpace; |
| Rectangle aItemRect( aPos, aSz ); |
| MenupopupValue aVal( nTextPos-GUTTERBORDER, aItemRect ); |
| bNativeOk = pWin->DrawNativeControl( CTRL_MENU_POPUP, PART_MENU_SEPARATOR, |
| aItemRect, |
| nState, |
| aVal, |
| OUString() ); |
| } |
| if( ! bNativeOk ) |
| { |
| 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 ) ); |
| MenupopupValue aVal( nTextPos-GUTTERBORDER, Rectangle( aPos, pData->aSz ) ); |
| pWin->DrawNativeControl( CTRL_MENU_POPUP, nPart, |
| aCheckRect, |
| nState, |
| aVal, |
| 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; |
| sal_uInt16 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 ) ); |
| } |
| // how much space is there for the text ? |
| long nMaxItemTextWidth = aOutSz.Width() - aTmpPos.X() - nExtra - nOuterSpace; |
| if( !bIsMenuBar && pData->aAccelKey.GetCode() && !ImplAccelDisabled() ) |
| { |
| XubString aAccText = pData->aAccelKey.GetName(); |
| nMaxItemTextWidth -= pWin->GetTextWidth( aAccText ) + 3*nExtra; |
| } |
| if( !bIsMenuBar && pData->pSubMenu ) |
| { |
| nMaxItemTextWidth -= nFontHeight - nExtra; |
| } |
| String aItemText( getShortenedString( pData->aText, pWin, nMaxItemTextWidth ) ); |
| pWin->DrawCtrlText( aTmpPos, aItemText, 0, aItemText.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 ( 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( sal_uInt16 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 ( sal_uLong n = GetItemList()->Count(); n && !pSelMenu; ) |
| { |
| MenuItemData* pData = GetItemList()->GetDataFromPos( --n ); |
| |
| if ( pData->pSubMenu ) |
| pSelMenu = pData->pSubMenu->ImplFindSelectMenu(); |
| } |
| |
| return pSelMenu; |
| } |
| |
| Menu* Menu::ImplFindMenu( sal_uInt16 nItemId ) |
| { |
| Menu* pSelMenu = NULL; |
| |
| for ( sal_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( sal_Bool bCheckPopups, sal_Bool bRemoveEmptyPopups ) |
| { |
| for ( sal_uInt16 n = 0; n < GetItemCount(); n++ ) |
| { |
| sal_Bool bRemove = sal_False; |
| MenuItemData* pItem = pItemList->GetDataFromPos( n ); |
| if ( pItem->eType == MENUITEM_SEPARATOR ) |
| { |
| if ( !n || ( GetItemType( n-1 ) == MENUITEM_SEPARATOR ) ) |
| bRemove = sal_True; |
| } |
| else |
| bRemove = !pItem->bEnabled; |
| |
| if ( bCheckPopups && pItem->pSubMenu ) |
| { |
| pItem->pSubMenu->RemoveDisabledEntries( sal_True ); |
| if ( bRemoveEmptyPopups && !pItem->pSubMenu->GetItemCount() ) |
| bRemove = sal_True; |
| } |
| |
| if ( bRemove ) |
| RemoveItem( n-- ); |
| } |
| |
| if ( GetItemCount() ) |
| { |
| sal_uInt16 nLast = GetItemCount() - 1; |
| MenuItemData* pItem = pItemList->GetDataFromPos( nLast ); |
| if ( pItem->eType == MENUITEM_SEPARATOR ) |
| RemoveItem( nLast ); |
| } |
| delete mpLayoutData, mpLayoutData = NULL; |
| } |
| |
| sal_Bool Menu::HasValidEntries( sal_Bool bCheckPopups ) |
| { |
| sal_Bool bValidEntries = sal_False; |
| sal_uInt16 nCount = GetItemCount(); |
| for ( sal_uInt16 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( sal_True ); |
| else |
| bValidEntries = sal_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, sal_False, true ); |
| } |
| else |
| { |
| MenuFloatingWindow* pFloat = (MenuFloatingWindow*)pWindow; |
| ImplPaint( pWindow, pFloat->nScrollerHeight, pFloat->ImplGetStartY(), 0, sal_False, true ); |
| } |
| } |
| } |
| |
| String Menu::GetDisplayText() const |
| { |
| if( ! mpLayoutData ) |
| ImplFillLayoutData(); |
| return mpLayoutData ? mpLayoutData->m_aDisplayText : String(); |
| } |
| |
| Rectangle Menu::GetCharacterBounds( sal_uInt16 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, sal_uInt16& 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( sal_uInt16 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 ); |
| } |
| |
| sal_uInt16 Menu::GetDisplayItemId( long nLine ) const |
| { |
| sal_uInt16 nItemId = 0; |
| if( ! mpLayoutData ) |
| ImplFillLayoutData(); |
| if( mpLayoutData && ( nLine >= 0 ) && ( nLine < (long)mpLayoutData->m_aLineItemIds.size() ) ) |
| nItemId = mpLayoutData->m_aLineItemIds[nLine]; |
| return nItemId; |
| } |
| |
| sal_Bool Menu::ConvertPoint( Point& rPoint, Window* pReferenceWindow ) const |
| { |
| sal_Bool bRet = sal_False; |
| if( pWindow && pReferenceWindow ) |
| { |
| rPoint = pReferenceWindow->OutputToAbsoluteScreenPixel( rPoint ); |
| rPoint = pWindow->AbsoluteScreenToOutputPixel( rPoint ); |
| bRet = sal_True; |
| } |
| return bRet; |
| } |
| |
| Rectangle Menu::GetBoundingRectangle( sal_uInt16 nPos ) const |
| { |
| Rectangle aRet; |
| |
| if( ! mpLayoutData ) |
| ImplFillLayoutData(); |
| if( mpLayoutData ) |
| { |
| std::map< sal_uInt16, Rectangle >::const_iterator it = mpLayoutData->m_aVisibleItemBoundRects.find( nPos ); |
| if( it != mpLayoutData->m_aVisibleItemBoundRects.end() ) |
| aRet = it->second; |
| } |
| return aRet; |
| } |
| |
| void Menu::SetAccessibleName( sal_uInt16 nItemId, const XubString& rStr ) |
| { |
| sal_uInt16 nPos; |
| MenuItemData* pData = pItemList->GetData( nItemId, nPos ); |
| |
| if ( pData && !rStr.Equals( pData->aAccessibleName ) ) |
| { |
| pData->aAccessibleName = rStr; |
| ImplCallEventListeners( VCLEVENT_MENU_ACCESSIBLENAMECHANGED, nPos ); |
| } |
| } |
| |
| XubString Menu::GetAccessibleName( sal_uInt16 nItemId ) const |
| { |
| MenuItemData* pData = pItemList->GetData( nItemId ); |
| |
| if ( pData ) |
| return pData->aAccessibleName; |
| else |
| return ImplGetSVEmptyStr(); |
| } |
| |
| void Menu::SetAccessibleDescription( sal_uInt16 nItemId, const XubString& rStr ) |
| { |
| MenuItemData* pData = pItemList->GetData( nItemId ); |
| |
| if ( pData ) |
| pData->aAccessibleDescription = rStr; |
| } |
| |
| XubString Menu::GetAccessibleDescription( sal_uInt16 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; |
| } |
| |
| sal_Bool Menu::GetSystemMenuData( SystemMenuData* pData ) const |
| { |
| Menu* pMenu = (Menu*)this; |
| if( pData && pMenu->ImplGetSalMenu() ) |
| { |
| pMenu->ImplGetSalMenu()->GetSystemMenuData( pData ); |
| return sal_True; |
| } |
| else |
| return sal_False; |
| } |
| |
| bool Menu::IsHighlighted( sal_uInt16 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( sal_uInt16 nItemPos ) |
| { |
| if ( pWindow ) |
| { |
| if ( bIsMenuBar ) |
| { |
| MenuBarWindow* pMenuWin = static_cast< MenuBarWindow* >( pWindow ); |
| pMenuWin->SetAutoPopup( sal_False ); |
| pMenuWin->ChangeHighlightItem( nItemPos, sal_False ); |
| } |
| else |
| { |
| static_cast< MenuFloatingWindow* >( pWindow )->ChangeHighlightItem( nItemPos, sal_False ); |
| } |
| } |
| } |
| |
| // ----------- |
| // - MenuBar - |
| // ----------- |
| |
| MenuBar::MenuBar() : Menu( sal_True ) |
| { |
| mbDisplayable = sal_True; |
| mbCloserVisible = sal_False; |
| mbFloatBtnVisible = sal_False; |
| mbHideBtnVisible = sal_False; |
| } |
| |
| MenuBar::MenuBar( const MenuBar& rMenu ) : Menu( sal_True ) |
| { |
| mbDisplayable = sal_True; |
| mbCloserVisible = sal_False; |
| mbFloatBtnVisible = sal_False; |
| mbHideBtnVisible = sal_False; |
| *this = rMenu; |
| bIsMenuBar = sal_True; |
| } |
| |
| MenuBar::MenuBar( const ResId& rResId ) : Menu ( sal_True ) |
| { |
| mbDisplayable = sal_True; |
| mbCloserVisible = sal_False; |
| mbFloatBtnVisible = sal_False; |
| mbHideBtnVisible = sal_False; |
| ImplLoadRes( rResId ); |
| } |
| |
| MenuBar::~MenuBar() |
| { |
| ImplDestroy( this, sal_True ); |
| } |
| |
| void MenuBar::ShowCloser( sal_Bool bShow ) |
| { |
| ShowButtons( bShow, mbFloatBtnVisible, mbHideBtnVisible ); |
| } |
| |
| void MenuBar::ShowFloatButton( sal_Bool bShow ) |
| { |
| ShowButtons( mbCloserVisible, bShow, mbHideBtnVisible ); |
| } |
| |
| void MenuBar::ShowHideButton( sal_Bool bShow ) |
| { |
| ShowButtons( mbCloserVisible, mbFloatBtnVisible, bShow ); |
| } |
| |
| void MenuBar::ShowButtons( sal_Bool bClose, sal_Bool bFloat, sal_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( sal_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, sal_Bool bDelete ) |
| { |
| MenuBarWindow* pWindow = (MenuBarWindow*) pMenu->ImplGetWindow(); |
| if ( pWindow && bDelete ) |
| { |
| pWindow->KillActivePopup(); |
| delete pWindow; |
| } |
| pMenu->pWindow = NULL; |
| } |
| |
| sal_Bool MenuBar::ImplHandleKeyEvent( const KeyEvent& rKEvent, sal_Bool bFromMenu ) |
| { |
| sal_Bool bDone = sal_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( sal_uInt16 nId ) |
| { |
| MenuBarWindow* pMenuWin = (MenuBarWindow*) ImplGetWindow(); |
| |
| if( pMenuWin ) |
| { |
| pMenuWin->GrabFocus(); |
| nId = GetItemPos( nId ); |
| |
| // #99705# popup the selected menu |
| pMenuWin->SetAutoPopup( sal_True ); |
| if( ITEMPOS_INVALID != pMenuWin->nHighlightedItem ) |
| { |
| pMenuWin->KillActivePopup(); |
| pMenuWin->ChangeHighlightItem( ITEMPOS_INVALID, sal_False ); |
| } |
| if( nId != ITEMPOS_INVALID ) |
| pMenuWin->ChangeHighlightItem( nId, sal_False ); |
| } |
| } |
| |
| // ----------------------------------------------------------------------- |
| |
| // handler for native menu selection and command events |
| |
| sal_Bool MenuBar::HandleMenuActivateEvent( Menu *pMenu ) const |
| { |
| if( pMenu ) |
| { |
| ImplMenuDelData aDelData( this ); |
| |
| pMenu->pStartedFrom = (Menu*)this; |
| pMenu->bInCallback = sal_True; |
| pMenu->Activate(); |
| |
| if( !aDelData.isDeleted() ) |
| pMenu->bInCallback = sal_False; |
| } |
| return sal_True; |
| } |
| |
| sal_Bool MenuBar::HandleMenuDeActivateEvent( Menu *pMenu ) const |
| { |
| if( pMenu ) |
| { |
| ImplMenuDelData aDelData( this ); |
| |
| pMenu->pStartedFrom = (Menu*)this; |
| pMenu->bInCallback = sal_True; |
| pMenu->Deactivate(); |
| if( !aDelData.isDeleted() ) |
| pMenu->bInCallback = sal_False; |
| } |
| return sal_True; |
| } |
| |
| sal_Bool MenuBar::HandleMenuHighlightEvent( Menu *pMenu, sal_uInt16 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 sal_True; |
| } |
| else |
| return sal_False; |
| } |
| |
| sal_Bool MenuBar::HandleMenuCommandEvent( Menu *pMenu, sal_uInt16 nCommandEventId ) const |
| { |
| if( !pMenu ) |
| pMenu = ((Menu*) this)->ImplFindMenu( nCommandEventId ); |
| if( pMenu ) |
| { |
| pMenu->nSelectedId = nCommandEventId; |
| pMenu->pStartedFrom = (Menu*)this; |
| pMenu->ImplSelect(); |
| return sal_True; |
| } |
| else |
| return sal_False; |
| } |
| |
| sal_uInt16 MenuBar::AddMenuBarButton( const Image& i_rImage, const Link& i_rLink, sal_uInt16 i_nPos ) |
| { |
| return AddMenuBarButton( i_rImage, i_rLink, String(), i_nPos ); |
| } |
| |
| sal_uInt16 MenuBar::AddMenuBarButton( const Image& i_rImage, const Link& i_rLink, const String& i_rToolTip, sal_uInt16 i_nPos ) |
| { |
| return pWindow ? static_cast<MenuBarWindow*>(pWindow)->AddMenuBarButton( i_rImage, i_rLink, i_rToolTip, i_nPos ) : 0; |
| } |
| |
| void MenuBar::SetMenuBarButtonHighlightHdl( sal_uInt16 nId, const Link& rLink ) |
| { |
| if( pWindow ) |
| static_cast<MenuBarWindow*>(pWindow)->SetMenuBarButtonHighlightHdl( nId, rLink ); |
| } |
| |
| Rectangle MenuBar::GetMenuBarButtonRectPixel( sal_uInt16 nId ) |
| { |
| return pWindow ? static_cast<MenuBarWindow*>(pWindow)->GetMenuBarButtonRectPixel( nId ) : Rectangle(); |
| } |
| |
| void MenuBar::RemoveMenuBarButton( sal_uInt16 nId ) |
| { |
| if( pWindow ) |
| static_cast<MenuBarWindow*>(pWindow)->RemoveMenuBarButton( nId ); |
| } |
| |
| sal_Bool MenuBar::HandleMenuButtonEvent( Menu *, sal_uInt16 i_nButtonId ) const |
| { |
| return static_cast<MenuBarWindow*>(pWindow)->HandleMenuButtonEvent( i_nButtonId ); |
| } |
| |
| // ----------------------------------------------------------------------- |
| |
| // sal_Bool PopupMenu::bAnyPopupInExecute = sal_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 |
| } |
| |
| sal_Bool PopupMenu::IsInExecute() |
| { |
| return GetActivePopupMenu() ? sal_True : sal_False; |
| } |
| |
| PopupMenu* PopupMenu::GetActivePopupMenu() |
| { |
| ImplSVData* pSVData = ImplGetSVData(); |
| return pSVData->maAppData.mpActivePopupMenu; |
| } |
| |
| void PopupMenu::EndExecute( sal_uInt16 nSelectId ) |
| { |
| if ( ImplGetWindow() ) |
| ImplGetFloatingWindow()->EndExecute( nSelectId ); |
| } |
| |
| void PopupMenu::SelectEntry( sal_uInt16 nId ) |
| { |
| if ( ImplGetWindow() ) |
| { |
| if( nId != ITEMPOS_INVALID ) |
| { |
| sal_uInt16 nPos; |
| MenuItemData* pData = GetItemList()->GetData( nId, nPos ); |
| if ( pData->pSubMenu ) |
| ImplGetFloatingWindow()->ChangeHighlightItem( nPos, sal_True ); |
| else |
| ImplGetFloatingWindow()->EndExecute( nId ); |
| } |
| else |
| { |
| MenuFloatingWindow* pFloat = ImplGetFloatingWindow(); |
| pFloat->GrabFocus(); |
| sal_uInt16 nPos; |
| for( nPos = 0; nPos < GetItemList()->Count(); nPos++ ) |
| { |
| MenuItemData* pData = (MenuItemData*)GetItemList()->GetObject( nPos ); |
| if( pData->pSubMenu ) |
| { |
| pFloat->KillActivePopup(); |
| } |
| } |
| pFloat->ChangeHighlightItem( ITEMPOS_INVALID, sal_False ); |
| } |
| } |
| } |
| |
| void PopupMenu::SetSelectedEntry( sal_uInt16 nId ) |
| { |
| nSelectedId = nId; |
| } |
| |
| sal_uInt16 PopupMenu::Execute( Window* pExecWindow, const Point& rPopupPos ) |
| { |
| return Execute( pExecWindow, Rectangle( rPopupPos, rPopupPos ), POPUPMENU_EXECUTE_DOWN ); |
| } |
| |
| sal_uInt16 PopupMenu::Execute( Window* pExecWindow, const Rectangle& rRect, sal_uInt16 nFlags ) |
| { |
| ENSURE_OR_RETURN( pExecWindow, "PopupMenu::Execute: need a non-NULL window!", 0 ); |
| |
| |
| sal_uLong nPopupModeFlags = 0; |
| if ( nFlags & POPUPMENU_EXECUTE_DOWN ) |
| nPopupModeFlags = FLOATWIN_POPUPMODE_DOWN; |
| 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, sal_False ); |
| } |
| |
| sal_uInt16 PopupMenu::ImplExecute( Window* pW, const Rectangle& rRect, sal_uLong nPopupModeFlags, Menu* pSFrom, sal_Bool bPreSelectFirst ) |
| { |
| if ( !pSFrom && ( PopupMenu::IsInExecute() || !GetItemCount() ) ) |
| return 0; |
| |
| delete mpLayoutData, mpLayoutData = NULL; |
| |
| ImplSVData* pSVData = ImplGetSVData(); |
| |
| pStartedFrom = pSFrom; |
| nSelectedId = 0; |
| bCanceled = sal_False; |
| |
| sal_uLong nFocusId = 0; |
| sal_Bool bRealExecute = sal_False; |
| if ( !pStartedFrom ) |
| { |
| pSVData->maWinData.mbNoDeactivate = sal_True; |
| nFocusId = Window::SaveFocus(); |
| bRealExecute = sal_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 = sal_True; // hier schon setzen, falls Activate ueberladen |
| Activate(); |
| bInCallback = sal_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; |
| |
| |
| sal_uInt16 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 ); |
| sal_uInt16 nmPos; |
| pData = pItemList->GetData( pData->nId, nmPos ); |
| pData->bIsTemporary = sal_True; |
| ImplCallEventListeners(VCLEVENT_MENU_SUBMENUCHANGED,nmPos); |
| } |
| } |
| 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( sal_True ); |
| sal_uInt16 nStart = ImplGetFirstVisible(); |
| sal_uInt16 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 ) |
| { |
| sal_uInt16 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 ) |
| { |
| sal_uInt16 nCount = (sal_uInt16)pItemList->Count(); |
| for ( sal_uInt16 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, sal_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 = sal_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; |
| } |
| |
| sal_uInt16 PopupMenu::ImplCalcVisEntries( long nMaxHeight, sal_uInt16 nStartEntry, sal_uInt16* pLastVisible ) const |
| { |
| nMaxHeight -= 2 * ImplGetFloatingWindow()->GetScrollerHeight(); |
| |
| long nHeight = 0; |
| sal_uInt16 nEntries = (sal_uInt16) pItemList->Count(); |
| sal_uInt16 nVisEntries = 0; |
| |
| if ( pLastVisible ) |
| *pLastVisible = 0; |
| |
| for ( sal_uInt16 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( sal_uInt16 nEntries ) const |
| { |
| long nHeight = 0; |
| |
| sal_uInt16 nFound = 0; |
| for ( sal_uInt16 n = 0; ( nFound < nEntries ) && ( n < pItemList->Count() ); n++ ) |
| { |
| if ( ImplIsVisible( (sal_uInt16) n ) ) |
| { |
| MenuItemData* pData = pItemList->GetDataFromPos( n ); |
| nHeight += pData->aSz.Height(); |
| nFound++; |
| } |
| } |
| |
| nHeight += 2*ImplGetFloatingWindow()->GetScrollerHeight(); |
| |
| return nHeight; |
| } |
| |
| |
| static void ImplInitMenuWindow( Window* pWin, sal_Bool bFont, sal_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( sal_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= sal_True; |
| pMenu = pMen; |
| pActivePopup = 0; |
| nSaveFocusId = 0; |
| bInExecute = sal_False; |
| bScrollMenu = sal_False; |
| nHighlightedItem = ITEMPOS_INVALID; |
| nMBDownPos = ITEMPOS_INVALID; |
| nPosInParent = ITEMPOS_INVALID; |
| nScrollerHeight = 0; |
| // nStartY = 0; |
| nBorder = EXTRASPACEY; |
| nFirstEntry = 0; |
| bScrollUp = sal_False; |
| bScrollDown = sal_False; |
| bIgnoreFirstMove = sal_True; |
| bKeyInput = sal_False; |
| |
| EnableSaveBackground(); |
| ImplInitMenuWindow( this, sal_True, sal_False ); |
| |
| SetPopupModeEndHdl( LINK( this, MenuFloatingWindow, PopupEnd ) ); |
| |
| aHighlightChangedTimer.SetTimeoutHdl( LINK( this, MenuFloatingWindow, HighlightChanged ) ); |
| aHighlightChangedTimer.SetTimeout( GetSettings().GetMouseSettings().GetMenuDelay() ); |
| aSubmenuCloseTimer.SetTimeout( GetSettings().GetMouseSettings().GetMenuDelay() ); |
| aSubmenuCloseTimer.SetTimeoutHdl( LINK( this, MenuFloatingWindow, SubmenuClose ) ); |
| aScrollTimer.SetTimeoutHdl( LINK( this, MenuFloatingWindow, AutoScroll ) ); |
| |
| AddEventListener( LINK( this, MenuFloatingWindow, ShowHideListener ) ); |
| } |
| |
| void MenuFloatingWindow::doShutdown() |
| { |
| if( pMenu ) |
| { |
| // #105373# notify toolkit that highlight was removed |
| // otherwise the entry will not be read when the menu is opened again |
| if( nHighlightedItem != ITEMPOS_INVALID ) |
| pMenu->ImplCallEventListeners( VCLEVENT_MENU_DEHIGHLIGHT, nHighlightedItem ); |
| pMenu->SetHightlightItem(ITEMPOS_INVALID); |
| if( !bKeyInput && pMenu && pMenu->pStartedFrom && !pMenu->pStartedFrom->bIsMenuBar ) |
| { |
| // #102461# remove highlight in parent |
| MenuItemData* pData; |
| sal_uInt16 i, nCount = (sal_uInt16)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, sal_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 ( sal_uInt16 n = 0; n < nFirstEntry; n++ ) |
| nY += pMenu->GetItemList()->GetDataFromPos( n )->aSz.Height(); |
| } |
| return -nY; |
| } |
| |
| Region MenuFloatingWindow::ImplCalcClipRegion( sal_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, sal_Bool bMBDown ) |
| { |
| if( ! pMenu ) |
| return; |
| |
| long nY = nScrollerHeight; |
| long nMouseY = rMEvt.GetPosPixel().Y(); |
| Size aOutSz = GetOutputSizePixel(); |
| if ( ( nMouseY >= nY ) && ( nMouseY < ( aOutSz.Height() - nY ) ) ) |
| { |
| sal_Bool bHighlighted = sal_False; |
| sal_uInt16 nCount = (sal_uInt16)pMenu->pItemList->Count(); |
| nY += ImplGetStartY(); // ggf. gescrollt. |
| for ( sal_uInt16 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 ) ) |
| { |
| sal_Bool bPopupArea = sal_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( (sal_uInt16)n, sal_False ); |
| } |
| |
| sal_Bool bAllowNewPopup = sal_True; |
| if ( pActivePopup ) |
| { |
| MenuItemData* pData = pMenu->pItemList->GetDataFromPos( n ); |
| bAllowNewPopup = pData && ( pData->pSubMenu != pActivePopup ); |
| if ( bAllowNewPopup ) |
| KillActivePopup(); |
| } |
| |
| if ( bPopupArea && bAllowNewPopup ) |
| { |
| HighlightChanged( NULL ); |
| } |
| } |
| else |
| { |
| if ( n != nHighlightedItem ) |
| { |
| ChangeHighlightItem( (sal_uInt16)n, sal_True ); |
| } |
| else if ( pItemData->nBits & MIB_POPUPSELECT ) |
| { |
| if ( bPopupArea && ( pActivePopup != pItemData->pSubMenu ) ) |
| HighlightChanged( NULL ); |
| } |
| } |
| bHighlighted = sal_True; |
| } |
| } |
| } |
| if ( !bHighlighted ) |
| ChangeHighlightItem( ITEMPOS_INVALID, sal_True ); |
| } |
| else |
| { |
| ImplScroll( rMEvt.GetPosPixel() ); |
| ChangeHighlightItem( ITEMPOS_INVALID, sal_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 = sal_True; |
| } |
| bInExecute = sal_False; |
| pMenu->bInCallback = sal_True; |
| pMenu->Deactivate(); |
| pMenu->bInCallback = sal_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 ) ) |
| { |
| sal_uLong nOldFlags = GetPopupModeFlags(); |
| SetPopupModeFlags( GetPopupModeFlags() | FLOATWIN_POPUPMODE_NOAPPFOCUSCLOSE ); |
| KillActivePopup(); |
| SetPopupModeFlags( nOldFlags ); |
| } |
| if ( pItemData->bEnabled && pItemData->pSubMenu && pItemData->pSubMenu->GetItemCount() && ( pItemData->pSubMenu != pActivePopup ) ) |
| { |
| pActivePopup = (PopupMenu*)pItemData->pSubMenu; |
| long nY = nScrollerHeight+ImplGetStartY(); |
| MenuItemData* pData = 0; |
| for ( sal_uLong n = 0; n < nHighlightedItem; n++ ) |
| { |
| pData = pMenu->pItemList->GetDataFromPos( n ); |
| nY += pData->aSz.Height(); |
| } |
| pData = pMenu->pItemList->GetDataFromPos( nHighlightedItem ); |
| Size MySize = GetOutputSizePixel(); |
| // Point 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; |
| sal_uLong nOldFlags = GetPopupModeFlags(); |
| SetPopupModeFlags( GetPopupModeFlags() | FLOATWIN_POPUPMODE_NOAPPFOCUSCLOSE ); |
| sal_uInt16 nRet = pActivePopup->ImplExecute( this, Rectangle( aItemTopLeft, aItemBottomRight ), FLOATWIN_POPUPMODE_RIGHT, pMenu, pTimer ? sal_False : sal_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( sal_Bool b ) |
| { |
| bScrollMenu = b; |
| nScrollerHeight = b ? (sal_uInt16) GetSettings().GetStyleSettings().GetScrollBarSize() /2 : 0; |
| bScrollDown = sal_True; |
| ImplInitClipRegion(); |
| } |
| |
| void MenuFloatingWindow::Execute() |
| { |
| ImplSVData* pSVData = ImplGetSVData(); |
| |
| pSVData->maAppData.mpActivePopupMenu = (PopupMenu*)pMenu; |
| |
| bInExecute = sal_True; |
| // bCallingSelect = sal_False; |
| |
| while ( bInExecute ) |
| Application::Yield(); |
| |
| pSVData->maAppData.mpActivePopupMenu = NULL; |
| |
| // while ( bCallingSelect ) |
| // Application::Yield(); |
| } |
| |
| void MenuFloatingWindow::StopExecute( sal_uLong nFocusId ) |
| { |
| // Focus wieder herstellen |
| // (kann schon im Select wieder hergestellt wurden sein) |
| if ( nSaveFocusId ) |
| { |
| Window::EndSaveFocus( nFocusId, sal_False ); |
| nFocusId = nSaveFocusId; |
| if ( nFocusId ) |
| { |
| nSaveFocusId = 0; |
| ImplGetSVData()->maWinData.mbNoDeactivate = sal_False; |
| } |
| } |
| ImplEndPopupMode( 0, nFocusId ); |
| |
| aHighlightChangedTimer.Stop(); |
| bInExecute = sal_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 = sal_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 = sal_True; |
| pPopup->Deactivate(); |
| pPopup->bInCallback = sal_False; |
| if ( pPopup->ImplGetWindow() ) |
| { |
| pPopup->ImplGetFloatingWindow()->StopExecute(); |
| pPopup->ImplGetFloatingWindow()->doShutdown(); |
| pPopup->pWindow->doLazyDelete(); |
| pPopup->pWindow = NULL; |
| |
| Update(); |
| } |
| } |
| } |
| |
| void MenuFloatingWindow::EndExecute() |
| { |
| Menu* pStart = pMenu ? pMenu->ImplGetStartMenu() : NULL; |
| sal_uLong nFocusId = 0; |
| if ( pStart && pStart->bIsMenuBar ) |
| { |
| nFocusId = ((MenuBarWindow*)((MenuBar*)pStart)->ImplGetWindow())->GetFocusId(); |
| if ( nFocusId ) |
| { |
| ((MenuBarWindow*)((MenuBar*)pStart)->ImplGetWindow())->SetFocusId( 0 ); |
| ImplGetSVData()->maWinData.mbNoDeactivate = sal_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; |
| sal_uInt16 nItem = nHighlightedItem; |
| |
| pCleanUpFrom->StopExecute( nFocusId ); |
| |
| if ( nItem != ITEMPOS_INVALID && pM ) |
| { |
| MenuItemData* pItemData = pM->GetItemList()->GetDataFromPos( nItem ); |
| if ( pItemData && !pItemData->bIsTemporary ) |
| { |
| pM->nSelectedId = pItemData->nId; |
| if ( pStart ) |
| pStart->nSelectedId = pItemData->nId; |
| |
| pM->ImplSelect(); |
| } |
| } |
| } |
| |
| void MenuFloatingWindow::EndExecute( sal_uInt16 nId ) |
| { |
| sal_uInt16 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, sal_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 |
| sal_uInt16 _nMBDownPos = nMBDownPos; |
| nMBDownPos = ITEMPOS_INVALID; |
| if ( pData && pData->bEnabled && ( pData->eType != MENUITEM_SEPARATOR ) ) |
| { |
| if ( !pData->pSubMenu ) |
| { |
| EndExecute(); |
| } |
| else if ( ( pData->nBits & MIB_POPUPSELECT ) && ( nHighlightedItem == _nMBDownPos ) && ( rMEvt.GetClicks() == 2 ) ) |
| { |
| // 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, sal_False ); |
| #ifdef OS2 |
| } |
| #endif |
| |
| if ( IsScrollMenu() ) |
| ImplScroll( rMEvt.GetPosPixel() ); |
| } |
| else |
| #ifdef OS2 |
| if ( ImplHilite(rMEvt) ) |
| #endif |
| { |
| aSubmenuCloseTimer.Stop(); |
| if( bIgnoreFirstMove ) |
| bIgnoreFirstMove = sal_False; |
| else |
| ImplHighlightItem( rMEvt, sal_False ); |
| } |
| } |
| |
| void MenuFloatingWindow::ImplScroll( sal_Bool bUp ) |
| { |
| KillActivePopup(); |
| Update(); |
| |
| if( ! pMenu ) |
| return; |
| |
| HighlightItem( nHighlightedItem, sal_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 = sal_True; |
| ImplDrawScroller( sal_False ); |
| } |
| |
| if ( pMenu->ImplGetPrevVisible( nFirstEntry ) == ITEMPOS_INVALID ) |
| { |
| bScrollUp = sal_False; |
| ImplDrawScroller( sal_True ); |
| } |
| |
| Scroll( 0, nScrollEntryHeight, ImplCalcClipRegion( sal_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 = sal_True; |
| ImplDrawScroller( sal_True ); |
| } |
| |
| long nHeight = GetOutputSizePixel().Height(); |
| sal_uInt16 nLastVisible; |
| ((PopupMenu*)pMenu)->ImplCalcVisEntries( nHeight, nFirstEntry, &nLastVisible ); |
| if ( pMenu->ImplGetNextVisible( nLastVisible ) == ITEMPOS_INVALID ) |
| { |
| bScrollDown = sal_False; |
| ImplDrawScroller( sal_False ); |
| } |
| |
| // nStartY -= nEntryHeight; |
| Scroll( 0, -nScrollEntryHeight, ImplCalcClipRegion( sal_False ).GetBoundRect(), SCROLL_CLIP ); |
| } |
| |
| HighlightItem( nHighlightedItem, sal_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( sal_True ); |
| nDelta = nY - nMouseY; |
| } |
| else if ( bScrollDown && ( nMouseY > ( aOutSz.Height() - nY ) ) ) |
| { |
| ImplScroll( sal_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( sal_uInt16 n, sal_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, sal_False ); |
| pMenu->ImplCallEventListeners( VCLEVENT_MENU_DEHIGHLIGHT, nHighlightedItem ); |
| } |
| |
| nHighlightedItem = (sal_uInt16)n; |
| DBG_ASSERT( pMenu->ImplIsVisible( nHighlightedItem ) || nHighlightedItem == ITEMPOS_INVALID, "ChangeHighlightItem: Not visible!" ); |
| if( nHighlightedItem != ITEMPOS_INVALID ) |
| { |
| if( pMenu->pStartedFrom && !pMenu->pStartedFrom->bIsMenuBar ) |
| { |
| // #102461# make sure parent entry is highlighted as well |
| MenuItemData* pData; |
| sal_uInt16 i, nCount = (sal_uInt16)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, sal_True ); |
| pPWin->nHighlightedItem = i; |
| } |
| } |
| } |
| HighlightItem( nHighlightedItem, sal_True ); |
| pMenu->SetHightlightItem(nHighlightedItem); |
| pMenu->ImplCallHighlight( nHighlightedItem ); |
| } |
| else |
| pMenu->nSelectedId = 0; |
| |
| if ( bStartPopupTimer ) |
| { |
| // #102438# Menu items are not selectable |
| // If a menu item is selected by an AT-tool via the XAccessibleAction, XAccessibleValue |
| // or XAccessibleSelection interface, and the parent popup menus are not executed yet, |
| // the parent popup menus must be executed SYNCHRONOUSLY, before the menu item is selected. |
| if ( GetSettings().GetMouseSettings().GetMenuDelay() ) |
| aHighlightChangedTimer.Start(); |
| else |
| HighlightChanged( &aHighlightChangedTimer ); |
| } |
| } |
| |
| void MenuFloatingWindow::HighlightItem( sal_uInt16 nPos, sal_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; |
| |
| sal_uInt16 nCount = (sal_uInt16)pMenu->pItemList->Count(); |
| for ( sal_uInt16 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 ) |
| { |
| sal_Bool bRestoreLineColor = sal_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() ) ); |
| MenupopupValue aVal( pMenu->nTextPos-GUTTERBORDER, aItemRect ); |
| DrawNativeControl( CTRL_MENU_POPUP, PART_ENTIRE_CONTROL, |
| aCtrlRect, |
| CTRL_STATE_ENABLED, |
| aVal, |
| OUString() ); |
| if( bHighlight && |
| IsNativeControlSupported( CTRL_MENU_POPUP, PART_MENU_ITEM ) ) |
| { |
| bDrawItemRect = false; |
| if( sal_False == DrawNativeControl( CTRL_MENU_POPUP, PART_MENU_ITEM, |
| aItemRect, |
| CTRL_STATE_SELECTED | ( pData->bEnabled? CTRL_STATE_ENABLED: 0 ), |
| aVal, |
| OUString() ) ) |
| { |
| bDrawItemRect = bHighlight; |
| } |
| } |
| else |
| bDrawItemRect = bHighlight; |
| Pop(); |
| } |
| if( bDrawItemRect ) |
| { |
| if ( bHighlight ) |
| { |
| if( pData->bEnabled ) |
| SetFillColor( GetSettings().GetStyleSettings().GetMenuHighlightColor() ); |
| else |
| { |
| SetFillColor(); |
| oldLineColor = GetLineColor(); |
| SetLineColor( GetSettings().GetStyleSettings().GetMenuHighlightColor() ); |
| bRestoreLineColor = sal_True; |
| } |
| } |
| else |
| SetFillColor( GetSettings().GetStyleSettings().GetMenuColor() ); |
| |
| DrawRect( aItemRect ); |
| } |
| pMenu->ImplPaint( this, nScrollerHeight, nStartY, pData, bHighlight ); |
| if( bRestoreLineColor ) |
| SetLineColor( oldLineColor ); |
| } |
| return; |
| } |
| |
| nY += pData->aSz.Height(); |
| } |
| } |
| |
| Rectangle MenuFloatingWindow::ImplGetItemRect( sal_uInt16 nPos ) |
| { |
| if( ! pMenu ) |
| return Rectangle(); |
| |
| Rectangle aRect; |
| Size aSz = GetOutputSizePixel(); |
| long nStartY = ImplGetStartY(); |
| long nY = nScrollerHeight+nStartY; |
| long nX = 0; |
| |
| if ( pMenu->pLogo ) |
| nX = pMenu->pLogo->aBitmap.GetSizePixel().Width(); |
| |
| sal_uInt16 nCount = (sal_uInt16)pMenu->pItemList->Count(); |
| for ( sal_uInt16 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( sal_Bool bUp, sal_Bool bHomeEnd ) |
| { |
| if( ! pMenu ) |
| return; |
| |
| const StyleSettings& rSettings = GetSettings().GetStyleSettings(); |
| |
| sal_uInt16 n = nHighlightedItem; |
| if ( n == ITEMPOS_INVALID ) |
| { |
| if ( bUp ) |
| n = 0; |
| else |
| n = pMenu->GetItemCount()-1; |
| } |
| |
| sal_uInt16 nLoop = n; |
| |
| if( bHomeEnd ) |
| { |
| // absolute positioning |
| if( bUp ) |
| { |
| n = pMenu->GetItemCount(); |
| nLoop = n-1; |
| } |
| else |
| { |
| n = (sal_uInt16)-1; |
| nLoop = n+1; |
| } |
| } |
| |
| do |
| { |
| if ( bUp ) |
| { |
| if ( n ) |
| n--; |
| else |
| if ( !IsScrollMenu() || ( nHighlightedItem == ITEMPOS_INVALID ) ) |
| n = pMenu->GetItemCount()-1; |
| else |
| break; |
| } |
| else |
| { |
| n++; |
| if ( n >= pMenu->GetItemCount() ) |
| { |
| if ( !IsScrollMenu() || ( nHighlightedItem == ITEMPOS_INVALID ) ) |
| n = 0; |
| else |
| break; |
| } |
| } |
| |
| MenuItemData* pData = (MenuItemData*)pMenu->GetItemList()->GetDataFromPos( n ); |
| if ( ( pData->bEnabled || !rSettings.GetSkipDisabledInMenus() ) |
| && ( pData->eType != MENUITEM_SEPARATOR ) && pMenu->ImplIsVisible( n ) && pMenu->ImplIsSelectable( n ) ) |
| { |
| // Selektion noch im sichtbaren Bereich? |
| if ( IsScrollMenu() ) |
| { |
| ChangeHighlightItem( ITEMPOS_INVALID, sal_False ); |
| |
| while ( n < nFirstEntry ) |
| ImplScroll( sal_True ); |
| |
| Size aOutSz = GetOutputSizePixel(); |
| sal_uInt16 nLastVisible; |
| ((PopupMenu*)pMenu)->ImplCalcVisEntries( aOutSz.Height(), nFirstEntry, &nLastVisible ); |
| while ( n > nLastVisible ) |
| { |
| ImplScroll( sal_False ); |
| ((PopupMenu*)pMenu)->ImplCalcVisEntries( aOutSz.Height(), nFirstEntry, &nLastVisible ); |
| } |
| } |
| ChangeHighlightItem( n, sal_False ); |
| break; |
| } |
| } while ( n != nLoop ); |
| } |
| |
| void MenuFloatingWindow::KeyInput( const KeyEvent& rKEvent ) |
| { |
| ImplDelData aDelData; |
| ImplAddDel( &aDelData ); |
| |
| sal_uInt16 nCode = rKEvent.GetKeyCode().GetCode(); |
| bKeyInput = sal_True; |
| switch ( nCode ) |
| { |
| case KEY_UP: |
| case KEY_DOWN: |
| { |
| ImplCursorUpDown( nCode == KEY_UP ); |
| } |
| break; |
| case KEY_END: |
| case KEY_HOME: |
| { |
| ImplCursorUpDown( nCode == KEY_END, sal_True ); |
| } |
| break; |
| case KEY_F6: |
| case KEY_ESCAPE: |
| { |
| // Ctrl-F6 acts like ESC here, the menu bar however will then put the focus in the document |
| if( nCode == KEY_F6 && !rKEvent.GetKeyCode().IsMod1() ) |
| break; |
| if( pMenu ) |
| { |
| if ( !pMenu->pStartedFrom ) |
| { |
| StopExecute(); |
| KillActivePopup(); |
| } |
| else if ( pMenu->pStartedFrom->bIsMenuBar ) |
| { |
| // Forward... |
| ((MenuBarWindow*)((MenuBar*)pMenu->pStartedFrom)->ImplGetWindow())->KeyInput( rKEvent ); |
| } |
| else |
| { |
| StopExecute(); |
| PopupMenu* pPopupMenu = (PopupMenu*)pMenu->pStartedFrom; |
| MenuFloatingWindow* pFloat = pPopupMenu->ImplGetFloatingWindow(); |
| pFloat->GrabFocus(); |
| pFloat->KillActivePopup(); |
| pPopupMenu->ImplCallHighlight(pFloat->nHighlightedItem); |
| } |
| } |
| } |
| break; |
| case KEY_LEFT: |
| { |
| if ( pMenu && pMenu->pStartedFrom ) |
| { |
| StopExecute(); |
| if ( pMenu->pStartedFrom->bIsMenuBar ) |
| { |
| // Forward... |
| ((MenuBarWindow*)((MenuBar*)pMenu->pStartedFrom)->ImplGetWindow())->KeyInput( rKEvent ); |
| } |
| else |
| { |
| MenuFloatingWindow* pFloat = ((PopupMenu*)pMenu->pStartedFrom)->ImplGetFloatingWindow(); |
| pFloat->GrabFocus(); |
| pFloat->KillActivePopup(); |
| sal_uInt16 highlightItem = pFloat->GetHighlightedItem(); |
| pFloat->ChangeHighlightItem(highlightItem, sal_False); |
| } |
| } |
| } |
| break; |
| case KEY_RIGHT: |
| { |
| if( pMenu ) |
| { |
| sal_Bool bDone = sal_False; |
| if ( nHighlightedItem != ITEMPOS_INVALID ) |
| { |
| MenuItemData* pData = pMenu->GetItemList()->GetDataFromPos( nHighlightedItem ); |
| if ( pData && pData->pSubMenu ) |
| { |
| HighlightChanged( 0 ); |
| bDone = sal_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(); |
| sal_uInt16 nPos = 0; |
| sal_uInt16 nDuplicates = 0; |
| MenuItemData* pData = (nCharCode && pMenu) ? pMenu->GetItemList()->SearchItem( nCharCode, rKEvent.GetKeyCode(), nPos, nDuplicates, nHighlightedItem ) : NULL; |
| if ( pData ) |
| { |
| if ( pData->pSubMenu || nDuplicates > 1 ) |
| { |
| ChangeHighlightItem( nPos, sal_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 = sal_False; |
| } |
| } |
| |
| void MenuFloatingWindow::Paint( const Rectangle& ) |
| { |
| if( ! pMenu ) |
| return; |
| |
| if( IsNativeControlSupported( CTRL_MENU_POPUP, PART_ENTIRE_CONTROL ) ) |
| { |
| SetClipRegion(); |
| long nX = pMenu->pLogo ? pMenu->pLogo->aBitmap.GetSizePixel().Width() : 0; |
| Size aPxSize( GetOutputSizePixel() ); |
| aPxSize.Width() -= nX; |
| ImplControlValue aVal( pMenu->nTextPos-GUTTERBORDER ); |
| DrawNativeControl( CTRL_MENU_POPUP, PART_ENTIRE_CONTROL, |
| Rectangle( Point( nX, 0 ), aPxSize ), |
| CTRL_STATE_ENABLED, |
| aVal, |
| OUString() ); |
| ImplInitClipRegion(); |
| } |
| if ( IsScrollMenu() ) |
| { |
| ImplDrawScroller( sal_True ); |
| ImplDrawScroller( sal_False ); |
| } |
| SetFillColor( GetSettings().GetStyleSettings().GetMenuColor() ); |
| pMenu->ImplPaint( this, nScrollerHeight, ImplGetStartY() ); |
| if ( nHighlightedItem != ITEMPOS_INVALID ) |
| HighlightItem( nHighlightedItem, sal_True ); |
| } |
| |
| void MenuFloatingWindow::ImplDrawScroller( sal_Bool bUp ) |
| { |
| if( ! pMenu ) |
| return; |
| |
| SetClipRegion(); |
| |
| Size aOutSz = GetOutputSizePixel(); |
| long nY = bUp ? 0 : ( aOutSz.Height() - nScrollerHeight ); |
| long nX = pMenu->pLogo ? pMenu->pLogo->aBitmap.GetSizePixel().Width() : 0; |
| Rectangle aRect( Point( nX, nY ), Size( aOutSz.Width()-nX, nScrollerHeight ) ); |
| |
| DecorationView aDecoView( this ); |
| SymbolType eSymbol = bUp ? SYMBOL_SPIN_UP : SYMBOL_SPIN_DOWN; |
| |
| sal_uInt16 nStyle = 0; |
| if ( ( bUp && !bScrollUp ) || ( !bUp && !bScrollDown ) ) |
| nStyle |= SYMBOL_DRAW_DISABLE; |
| |
| aDecoView.DrawSymbol( aRect, eSymbol, GetSettings().GetStyleSettings().GetButtonTextColor(), nStyle ); |
| |
| ImplInitClipRegion(); |
| } |
| |
| void MenuFloatingWindow::RequestHelp( const HelpEvent& rHEvt ) |
| { |
| sal_uInt16 nId = nHighlightedItem; |
| Menu* pM = pMenu; |
| Window* pW = this; |
| |
| // #102618# Get item rect before destroying the window in EndExecute() call |
| Rectangle aHighlightRect( ImplGetItemRect( nHighlightedItem ) ); |
| |
| if ( rHEvt.GetMode() & (HELPMODE_CONTEXT | HELPMODE_EXTENDED) ) |
| { |
| nHighlightedItem = ITEMPOS_INVALID; |
| EndExecute(); |
| pW = NULL; |
| } |
| |
| if( !ImplHandleHelpEvent( pW, pM, nId, rHEvt, aHighlightRect ) ) |
| Window::RequestHelp( rHEvt ); |
| } |
| |
| void MenuFloatingWindow::StateChanged( StateChangedType nType ) |
| { |
| FloatingWindow::StateChanged( nType ); |
| |
| if ( ( nType == STATE_CHANGE_CONTROLFOREGROUND ) || ( nType == STATE_CHANGE_CONTROLBACKGROUND ) ) |
| { |
| ImplInitMenuWindow( this, sal_False, sal_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, sal_False, sal_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 = sal_True; |
| nSaveFocusId = 0; |
| bIgnoreFirstMove = sal_True; |
| bStayActive = sal_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( sal_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, sal_True, sal_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( sal_Bool bClose, sal_Bool bFloat, sal_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<sal_uInt16,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 ) |
| { |
| sal_uInt16 nPos = static_cast< sal_uInt16 >(reinterpret_cast<sal_IntPtr>(pEvent->GetData())); |
| aArg.nId = aCloser.GetItemId( nPos ); |
| } |
| std::map< sal_uInt16, 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( sal_Bool bPreSelectFirst ) |
| { |
| MenuItemData* pItemData = pMenu ? pMenu->GetItemList()->GetDataFromPos( nHighlightedItem ) : NULL; |
| if ( pItemData ) |
| { |
| bIgnoreFirstMove = sal_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 ( sal_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 = sal_True; |
| |
| pActivePopup->bInCallback = sal_True; |
| pActivePopup->Deactivate(); |
| pActivePopup->bInCallback = sal_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, sal_False, ImplGetFrameWindow()->ImplGetFrameData()->mbHasFocus, sal_False ); |
| } |
| } |
| |
| void MenuBarWindow::MouseButtonDown( const MouseEvent& rMEvt ) |
| { |
| mbAutoPopup = sal_True; |
| sal_uInt16 nEntry = ImplFindEntry( rMEvt.GetPosPixel() ); |
| if ( ( nEntry != ITEMPOS_INVALID ) && ( nEntry != nHighlightedItem ) ) |
| { |
| ChangeHighlightItem( nEntry, sal_False ); |
| } |
| else |
| { |
| KillActivePopup(); |
| ChangeHighlightItem( ITEMPOS_INVALID, sal_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 = sal_False; |
| return; |
| } |
| |
| sal_uInt16 nEntry = ImplFindEntry( rMEvt.GetPosPixel() ); |
| if ( ( nEntry != ITEMPOS_INVALID ) |
| #ifdef OS2 |
| && ( ImplHilite(rMEvt) ) |
| #endif |
| && ( nEntry != nHighlightedItem ) ) |
| ChangeHighlightItem( nEntry, sal_False ); |
| } |
| |
| void MenuBarWindow::ChangeHighlightItem( sal_uInt16 n, sal_Bool bSelectEntry, sal_Bool bAllowRestoreFocus, sal_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... |
| sal_Bool bJustActivated = sal_False; |
| if ( ( nHighlightedItem == ITEMPOS_INVALID ) && ( n != ITEMPOS_INVALID ) ) |
| { |
| ImplGetSVData()->maWinData.mbNoDeactivate = sal_True; |
| if( !bStayActive ) |
| { |
| // #105406# avoid saving the focus when we already have the focus |
| sal_Bool bNoSaveFocus = (this == ImplGetSVData()->maWinData.mpFocusWin ); |
| |
| if( nSaveFocusId ) |
| { |
| if( !ImplGetSVData()->maWinData.mbNoSaveFocus ) |
| { |
| // we didn't clean up last time |
| Window::EndSaveFocus( nSaveFocusId, sal_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 = sal_False; |
| pMenu->bInCallback = sal_True; // hier schon setzen, falls Activate ueberladen |
| pMenu->Activate(); |
| pMenu->bInCallback = sal_False; |
| bJustActivated = sal_True; |
| } |
| else if ( ( nHighlightedItem != ITEMPOS_INVALID ) && ( n == ITEMPOS_INVALID ) ) |
| { |
| pMenu->bInCallback = sal_True; |
| pMenu->Deactivate(); |
| pMenu->bInCallback = sal_False; |
| ImplGetSVData()->maWinData.mbNoDeactivate = sal_False; |
| if( !ImplGetSVData()->maWinData.mbNoSaveFocus ) |
| { |
| sal_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, sal_False ); |
| pMenu->ImplCallEventListeners( VCLEVENT_MENU_DEHIGHLIGHT, nHighlightedItem ); |
| } |
| |
| nHighlightedItem = (sal_uInt16)n; |
| DBG_ASSERT( ( nHighlightedItem == ITEMPOS_INVALID ) || pMenu->ImplIsVisible( nHighlightedItem ), "ChangeHighlightItem: Not visible!" ); |
| HighlightItem( nHighlightedItem, sal_True ); |
| pMenu->SetHightlightItem(nHighlightedItem); |
| pMenu->ImplCallHighlight( nHighlightedItem ); |
| |
| if( mbAutoPopup ) |
| ImplCreatePopup( bSelectEntry ); |
| |
| // #58935# #73659# Focus, wenn kein Popup drunter haengt... |
| if ( bJustActivated && !pActivePopup ) |
| GrabFocus(); |
| } |
| |
| void MenuBarWindow::HighlightItem( sal_uInt16 nPos, sal_Bool bHighlight ) |
| { |
| if( ! pMenu ) |
| return; |
| |
| long nX = 0; |
| sal_uLong nCount = pMenu->pItemList->Count(); |
| for ( sal_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( sal_uInt16 nPos ) |
| { |
| Rectangle aRect; |
| if( pMenu ) |
| { |
| long nX = 0; |
| sal_uLong nCount = pMenu->pItemList->Count(); |
| for ( sal_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 ); |
| } |
| |
| sal_Bool MenuBarWindow::ImplHandleKeyEvent( const KeyEvent& rKEvent, sal_Bool bFromMenu ) |
| { |
| if( ! pMenu ) |
| return sal_False; |
| |
| if ( pMenu->bInCallback ) |
| return sal_True; // schlucken |
| |
| sal_Bool bDone = sal_False; |
| sal_uInt16 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 sal_True; |
| } |
| } |
| |
| if ( nCode == KEY_MENU && !rKEvent.GetKeyCode().IsShift() ) // only F10, not Shift-F10 |
| { |
| mbAutoPopup = ImplGetSVData()->maNWFData.mbOpenMenuOnF10; |
| if ( nHighlightedItem == ITEMPOS_INVALID ) |
| { |
| ChangeHighlightItem( 0, sal_False ); |
| GrabFocus(); |
| } |
| else |
| { |
| ChangeHighlightItem( ITEMPOS_INVALID, sal_False ); |
| nSaveFocusId = 0; |
| } |
| bDone = sal_True; |
| } |
| else if ( bFromMenu ) |
| { |
| if ( ( nCode == KEY_LEFT ) || ( nCode == KEY_RIGHT ) || |
| ( nCode == KEY_HOME ) || ( nCode == KEY_END ) ) |
| { |
| sal_uInt16 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); |
| } |
| |
| sal_uInt16 nLoop = n; |
| |
| if( nCode == KEY_HOME ) |
| { n = (sal_uInt16)-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 ) ) |
| { |
| sal_Bool bDoSelect = sal_True; |
| if( ImplGetSVData()->maNWFData.mbOpenMenuOnF10 ) |
| bDoSelect = bWasHighlight; |
| ChangeHighlightItem( n, bDoSelect ); |
| break; |
| } |
| } while ( n != nLoop ); |
| bDone = sal_True; |
| } |
| else if ( nCode == KEY_RETURN ) |
| { |
| if( pActivePopup ) KillActivePopup(); |
| else |
| if ( !mbAutoPopup ) |
| { |
| ImplCreatePopup( sal_True ); |
| mbAutoPopup = sal_True; |
| } |
| bDone = sal_True; |
| } |
| else if ( ( nCode == KEY_UP ) || ( nCode == KEY_DOWN ) ) |
| { |
| if ( !mbAutoPopup ) |
| { |
| ImplCreatePopup( sal_True ); |
| mbAutoPopup = sal_True; |
| } |
| bDone = sal_True; |
| } |
| else if ( nCode == KEY_ESCAPE || ( nCode == KEY_F6 && rKEvent.GetKeyCode().IsMod1() ) ) |
| { |
| if( pActivePopup ) |
| { |
| // bring focus to menu bar without any open popup |
| mbAutoPopup = sal_False; |
| sal_uInt16 n = nHighlightedItem; |
| nHighlightedItem = ITEMPOS_INVALID; |
| bStayActive = sal_True; |
| ChangeHighlightItem( n, sal_False ); |
| bStayActive = sal_False; |
| KillActivePopup(); |
| GrabFocus(); |
| } |
| else |
| ChangeHighlightItem( ITEMPOS_INVALID, sal_False ); |
| |
| if( nCode == KEY_F6 && rKEvent.GetKeyCode().IsMod1() ) |
| { |
| // put focus into document |
| GrabFocusToDocument(); |
| } |
| |
| bDone = sal_True; |
| } |
| } |
| |
| if ( !bDone && ( bFromMenu || rKEvent.GetKeyCode().IsMod2() ) ) |
| { |
| xub_Unicode nCharCode = rKEvent.GetCharCode(); |
| if ( nCharCode ) |
| { |
| sal_uInt16 nEntry, nDuplicates; |
| MenuItemData* pData = pMenu->GetItemList()->SearchItem( nCharCode, rKEvent.GetKeyCode(), nEntry, nDuplicates, nHighlightedItem ); |
| if ( pData && (nEntry != ITEMPOS_INVALID) ) |
| { |
| mbAutoPopup = sal_True; |
| ChangeHighlightItem( nEntry, sal_True ); |
| bDone = sal_True; |
| } |
| else |
| { |
| // Wegen Systemmenu und anderen System-HotKeys, nur |
| // eigenstaendige Character-Kombinationen auswerten |
| sal_uInt16 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, sal_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(); |
| } |
| |
| sal_uInt16 MenuBarWindow::ImplFindEntry( const Point& rMousePos ) const |
| { |
| if( pMenu ) |
| { |
| long nX = 0; |
| sal_uInt16 nCount = (sal_uInt16)pMenu->pItemList->Count(); |
| for ( sal_uInt16 n = 0; n < nCount; n++ ) |
| { |
| MenuItemData* pData = pMenu->pItemList->GetDataFromPos( n ); |
| if ( pMenu->ImplIsVisible( n ) ) |
| { |
| nX += pData->aSz.Width(); |
| if ( nX > rMousePos.X() ) |
| return (sal_uInt16)n; |
| } |
| } |
| } |
| return ITEMPOS_INVALID; |
| } |
| |
| void MenuBarWindow::RequestHelp( const HelpEvent& rHEvt ) |
| { |
| sal_uInt16 nId = nHighlightedItem; |
| if ( rHEvt.GetMode() & (HELPMODE_CONTEXT | HELPMODE_EXTENDED) ) |
| ChangeHighlightItem( ITEMPOS_INVALID, sal_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, sal_False, sal_True ); |
| Invalidate(); |
| } |
| else if( pMenu ) |
| pMenu->ImplKillLayoutData(); |
| |
| } |
| |
| void MenuBarWindow::ImplLayoutChanged() |
| { |
| if( pMenu ) |
| { |
| ImplInitMenuWindow( this, sal_True, sal_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( sal_True ) ) |
| ChangeHighlightItem( ITEMPOS_INVALID, sal_False, sal_False ); |
| } |
| |
| void MenuBarWindow::GetFocus() |
| { |
| if ( nHighlightedItem == ITEMPOS_INVALID ) |
| { |
| mbAutoPopup = sal_False; // do not open menu when activated by focus handling like taskpane cycling |
| ChangeHighlightItem( 0, sal_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; |
| } |
| |
| sal_uInt16 MenuBarWindow::AddMenuBarButton( const Image& i_rImage, const Link& i_rLink, const String& i_rToolTip, sal_uInt16 i_nPos ) |
| { |
| // find first free button id |
| sal_uInt16 nId = IID_DOCUMENTCLOSE; |
| std::map< sal_uInt16, AddButtonEntry >::const_iterator it; |
| if( i_nPos > m_aAddButtons.size() ) |
| i_nPos = static_cast<sal_uInt16>(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( sal_uInt16 nId, const Link& rLink ) |
| { |
| std::map< sal_uInt16, AddButtonEntry >::iterator it = m_aAddButtons.find( nId ); |
| if( it != m_aAddButtons.end() ) |
| it->second.m_aHighlightLink = rLink; |
| } |
| |
| Rectangle MenuBarWindow::GetMenuBarButtonRectPixel( sal_uInt16 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( sal_uInt16 nId ) |
| { |
| sal_uInt16 nPos = aCloser.GetItemPos( nId ); |
| aCloser.RemoveItem( nPos ); |
| m_aAddButtons.erase( nId ); |
| aCloser.calcMinSize(); |
| ImplLayoutChanged(); |
| |
| if( pMenu->mpSalMenu ) |
| pMenu->mpSalMenu->RemoveMenuBarButton( nId ); |
| } |
| |
| bool MenuBarWindow::HandleMenuButtonEvent( sal_uInt16 i_nButtonId ) |
| { |
| std::map< sal_uInt16, 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 sal_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 ); |
| } |