update dev300-m58
[ooovba.git] / vcl / source / window / menu.cxx
blob1fe5c5f59d16438af6d0c5368e9dc01d3b664b9d
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: menu.cxx,v $
10 * $Revision: 1.165 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_vcl.hxx"
34 #include "svsys.h"
35 #include "vcl/salinst.hxx"
36 #include "tools/list.hxx"
37 #include "tools/debug.hxx"
38 #include "vcl/svdata.hxx"
39 #include "vcl/svapp.hxx"
40 #include "vcl/mnemonic.hxx"
41 #include "vcl/image.hxx"
42 #include "vcl/event.hxx"
43 #include "vcl/help.hxx"
44 #include "vcl/svids.hrc"
45 #include "vcl/floatwin.hxx"
46 #include "vcl/wrkwin.hxx"
47 #include "vcl/timer.hxx"
48 #include "vcl/sound.hxx"
49 #include "vcl/decoview.hxx"
50 #include "vcl/bitmap.hxx"
51 #include "tools/rc.h"
52 #include "vcl/menu.hxx"
53 #include "vcl/button.hxx"
54 #include "vcl/gradient.hxx"
55 #include "vcl/i18nhelp.hxx"
56 #include "vcl/taskpanelist.hxx"
57 #include "vcl/window.h"
58 #include "vcl/controllayout.hxx"
59 #include "vcl/toolbox.hxx"
60 #include "tools/stream.hxx"
61 #include "vcl/salmenu.hxx"
62 #include "vcl/salframe.hxx"
63 #include "vcl/dockingarea.hxx"
66 #include <com/sun/star/uno/Reference.h>
67 #include <com/sun/star/i18n/XCharacterClassification.hpp>
68 #include <com/sun/star/lang/XComponent.hpp>
69 #include <com/sun/star/accessibility/XAccessible.hpp>
70 #include <com/sun/star/accessibility/AccessibleRole.hpp>
71 #include <vcl/unowrap.hxx>
73 #include <vcl/unohelp.hxx>
74 #include <vcl/configsettings.hxx>
76 #include "vcl/lazydelete.hxx"
78 #include <map>
80 namespace vcl
83 struct MenuLayoutData : public ControlLayoutData
85 std::vector< USHORT > m_aLineItemIds;
86 std::vector< USHORT > m_aLineItemPositions;
87 std::map< USHORT, Rectangle > m_aVisibleItemBoundRects;
92 using namespace ::com::sun::star;
93 using namespace vcl;
95 DBG_NAME( Menu )
97 #define ITEMPOS_INVALID 0xFFFF
99 #define EXTRASPACEY 2
100 #define EXTRAITEMHEIGHT 4
102 // document closer
103 #define IID_DOCUMENTCLOSE 1
105 #ifdef OS2
107 #include <xwphook.h>
109 // return TRUE if hilite should be executed: left mouse button down
110 // or xwp mouse hook enabled
111 static BOOL ImplHilite( const MouseEvent& rMEvt )
113 static BOOL init = FALSE;
114 static HOOKCONFIG hc;
116 // read XWP settings at program startup
117 if (init == FALSE) {
118 BOOL rc;
119 ULONG cb = sizeof(HOOKCONFIG);
120 memset(&hc, 0, sizeof(HOOKCONFIG));
121 rc = PrfQueryProfileData( HINI_USER, INIAPP_XWPHOOK, INIKEY_HOOK_CONFIG,
122 &hc, &cb);
123 init = TRUE;
125 // check mouse left button
126 if (rMEvt.GetButtons() == MOUSE_LEFT)
127 return TRUE;
128 // return xwp flag
129 return hc.fSlidingMenus;
132 #endif
134 static BOOL ImplAccelDisabled()
136 // display of accelerator strings may be suppressed via configuration
137 static int nAccelDisabled = -1;
139 if( nAccelDisabled == -1 )
141 rtl::OUString aStr =
142 vcl::SettingsConfigItem::get()->
143 getValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Menu" ) ),
144 rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "SuppressAccelerators" ) ) );
145 nAccelDisabled = aStr.equalsIgnoreAsciiCaseAscii( "true" ) ? 1 : 0;
147 return (nAccelDisabled == 1) ? TRUE : FALSE;
150 struct MenuItemData
152 USHORT nId; // SV Id
153 MenuItemType eType; // MenuItem-Type
154 MenuItemBits nBits; // MenuItem-Bits
155 Menu* pSubMenu; // Pointer auf das SubMenu
156 Menu* pAutoSubMenu; // Pointer auf SubMenu aus Resource
157 XubString aText; // Menu-Text
158 XubString aHelpText; // Help-String
159 XubString aTipHelpText; // TipHelp-String (eg, expanded filenames)
160 XubString aCommandStr; // CommandString
161 XubString aHelpCommandStr; // Help command string (to reference external help)
162 ULONG nHelpId; // Help-Id
163 ULONG nUserValue; // User value
164 Image aImage; // Image
165 KeyCode aAccelKey; // Accelerator-Key
166 BOOL bChecked; // Checked
167 BOOL bEnabled; // Enabled
168 BOOL bVisible; // Visible (note: this flag will not override MENU_FLAG_HIDEDISABLEDENTRIES when true)
169 BOOL bIsTemporary; // Temporary inserted ('No selection possible')
170 BOOL bMirrorMode;
171 long nItemImageAngle;
172 Size aSz; // nur temporaer gueltig
173 XubString aAccessibleName; // accessible name
174 XubString aAccessibleDescription; // accessible description
176 SalMenuItem* pSalMenuItem; // access to native menu
178 MenuItemData() :
179 pSalMenuItem ( NULL )
181 MenuItemData( const XubString& rStr, const Image& rImage ) :
182 aText( rStr ),
183 aImage( rImage ),
184 pSalMenuItem ( NULL )
186 ~MenuItemData();
187 bool HasCheck()
189 return bChecked || ( nBits & ( MIB_RADIOCHECK | MIB_CHECKABLE | MIB_AUTOCHECK ) );
193 MenuItemData::~MenuItemData()
195 if( pAutoSubMenu )
197 ((PopupMenu*)pAutoSubMenu)->pRefAutoSubMenu = NULL;
198 delete pAutoSubMenu;
199 pAutoSubMenu = NULL;
201 if( pSalMenuItem )
202 ImplGetSVData()->mpDefInst->DestroyMenuItem( pSalMenuItem );
205 class MenuItemList : public List
207 private:
208 uno::Reference< i18n::XCharacterClassification > xCharClass;
211 public:
212 MenuItemList() : List( 16, 4 ) {}
213 ~MenuItemList();
215 MenuItemData* Insert( USHORT nId, MenuItemType eType, MenuItemBits nBits,
216 const XubString& rStr, const Image& rImage,
217 Menu* pMenu, USHORT nPos );
218 void InsertSeparator( USHORT nPos );
219 void Remove( USHORT nPos );
222 MenuItemData* GetData( USHORT nSVId, USHORT& rPos ) const;
223 MenuItemData* GetData( USHORT nSVId ) const
224 { USHORT nTemp; return GetData( nSVId, nTemp ); }
225 MenuItemData* GetDataFromPos( ULONG nPos ) const
226 { return (MenuItemData*)List::GetObject( nPos ); }
228 MenuItemData* SearchItem( xub_Unicode cSelectChar, KeyCode aKeyCode, USHORT& rPos, USHORT& nDuplicates, USHORT nCurrentPos ) const;
229 USHORT GetItemCount( xub_Unicode cSelectChar ) const;
230 USHORT GetItemCount( KeyCode aKeyCode ) const;
232 uno::Reference< i18n::XCharacterClassification > GetCharClass() const;
237 MenuItemList::~MenuItemList()
239 for ( ULONG n = Count(); n; )
241 MenuItemData* pData = GetDataFromPos( --n );
242 delete pData;
246 MenuItemData* MenuItemList::Insert( USHORT nId, MenuItemType eType,
247 MenuItemBits nBits,
248 const XubString& rStr, const Image& rImage,
249 Menu* pMenu, USHORT nPos )
251 MenuItemData* pData = new MenuItemData( rStr, rImage );
252 pData->nId = nId;
253 pData->eType = eType;
254 pData->nBits = nBits;
255 pData->pSubMenu = NULL;
256 pData->pAutoSubMenu = NULL;
257 pData->nHelpId = 0;
258 pData->nUserValue = 0;
259 pData->bChecked = FALSE;
260 pData->bEnabled = TRUE;
261 pData->bVisible = TRUE;
262 pData->bIsTemporary = FALSE;
263 pData->bMirrorMode = FALSE;
264 pData->nItemImageAngle = 0;
266 SalItemParams aSalMIData;
267 aSalMIData.nId = nId;
268 aSalMIData.eType = eType;
269 aSalMIData.nBits = nBits;
270 aSalMIData.pMenu = pMenu;
271 aSalMIData.aText = rStr;
272 aSalMIData.aImage = rImage;
274 // Native-support: returns NULL if not supported
275 pData->pSalMenuItem = ImplGetSVData()->mpDefInst->CreateMenuItem( &aSalMIData );
277 List::Insert( (void*)pData, nPos );
278 return pData;
281 void MenuItemList::InsertSeparator( USHORT nPos )
283 MenuItemData* pData = new MenuItemData;
284 pData->nId = 0;
285 pData->eType = MENUITEM_SEPARATOR;
286 pData->nBits = 0;
287 pData->pSubMenu = NULL;
288 pData->pAutoSubMenu = NULL;
289 pData->nHelpId = 0;
290 pData->nUserValue = 0;
291 pData->bChecked = FALSE;
292 pData->bEnabled = TRUE;
293 pData->bVisible = TRUE;
294 pData->bIsTemporary = FALSE;
295 pData->bMirrorMode = FALSE;
296 pData->nItemImageAngle = 0;
298 SalItemParams aSalMIData;
299 aSalMIData.nId = 0;
300 aSalMIData.eType = MENUITEM_SEPARATOR;
301 aSalMIData.nBits = 0;
302 aSalMIData.pMenu = NULL;
303 aSalMIData.aText = XubString();
304 aSalMIData.aImage = Image();
306 // Native-support: returns NULL if not supported
307 pData->pSalMenuItem = ImplGetSVData()->mpDefInst->CreateMenuItem( &aSalMIData );
309 List::Insert( (void*)pData, nPos );
312 void MenuItemList::Remove( USHORT nPos )
314 MenuItemData* pData = (MenuItemData*)List::Remove( (ULONG)nPos );
315 if ( pData )
316 delete pData;
319 MenuItemData* MenuItemList::GetData( USHORT nSVId, USHORT& rPos ) const
321 rPos = 0;
322 MenuItemData* pData = (MenuItemData*)GetObject( rPos );
323 while ( pData )
325 if ( pData->nId == nSVId )
326 return pData;
328 rPos++;
329 pData = (MenuItemData*)GetObject( rPos );
332 return NULL;
335 MenuItemData* MenuItemList::SearchItem( xub_Unicode cSelectChar, KeyCode aKeyCode, USHORT& rPos, USHORT& nDuplicates, USHORT nCurrentPos ) const
337 const vcl::I18nHelper& rI18nHelper = Application::GetSettings().GetUILocaleI18nHelper();
339 USHORT nListCount = (USHORT)Count();
341 // try character code first
342 nDuplicates = GetItemCount( cSelectChar ); // return number of duplicates
343 if( nDuplicates )
345 for ( rPos = 0; rPos < nListCount; rPos++)
347 MenuItemData* pData = GetDataFromPos( rPos );
348 if ( pData->bEnabled && rI18nHelper.MatchMnemonic( pData->aText, cSelectChar ) )
350 if( nDuplicates > 1 && rPos == nCurrentPos )
351 continue; // select next entry with the same mnemonic
352 else
353 return pData;
358 // nothing found, try keycode instead
359 nDuplicates = GetItemCount( aKeyCode ); // return number of duplicates
361 if( nDuplicates )
363 char ascii = 0;
364 if( aKeyCode.GetCode() >= KEY_A && aKeyCode.GetCode() <= KEY_Z )
365 ascii = sal::static_int_cast<char>('A' + (aKeyCode.GetCode() - KEY_A));
367 for ( rPos = 0; rPos < nListCount; rPos++)
369 MenuItemData* pData = GetDataFromPos( rPos );
370 if ( pData->bEnabled )
372 USHORT n = pData->aText.Search( '~' );
373 if ( n != STRING_NOTFOUND )
375 KeyCode mnKeyCode;
376 xub_Unicode mnUnicode = pData->aText.GetChar(n+1);
377 Window* pDefWindow = ImplGetDefaultWindow();
378 if( (pDefWindow && pDefWindow->ImplGetFrame()->MapUnicodeToKeyCode( mnUnicode, Application::GetSettings().GetUILanguage(), mnKeyCode )
379 && aKeyCode.GetCode() == mnKeyCode.GetCode())
380 || (ascii && rI18nHelper.MatchMnemonic( pData->aText, ascii ) ) )
383 if( nDuplicates > 1 && rPos == nCurrentPos )
384 continue; // select next entry with the same mnemonic
385 else
386 return pData;
393 return NULL;
396 USHORT MenuItemList::GetItemCount( xub_Unicode cSelectChar ) const
398 // returns number of entries with same mnemonic
399 const vcl::I18nHelper& rI18nHelper = Application::GetSettings().GetUILocaleI18nHelper();
401 USHORT nItems = 0, nPos;
402 for ( nPos = (USHORT)Count(); nPos; )
404 MenuItemData* pData = GetDataFromPos( --nPos );
405 if ( pData->bEnabled && rI18nHelper.MatchMnemonic( pData->aText, cSelectChar ) )
406 nItems++;
409 return nItems;
412 USHORT MenuItemList::GetItemCount( KeyCode aKeyCode ) const
414 // returns number of entries with same mnemonic
415 // uses key codes instead of character codes
416 const vcl::I18nHelper& rI18nHelper = Application::GetSettings().GetUILocaleI18nHelper();
417 char ascii = 0;
418 if( aKeyCode.GetCode() >= KEY_A && aKeyCode.GetCode() <= KEY_Z )
419 ascii = sal::static_int_cast<char>('A' + (aKeyCode.GetCode() - KEY_A));
421 USHORT nItems = 0, nPos;
422 for ( nPos = (USHORT)Count(); nPos; )
424 MenuItemData* pData = GetDataFromPos( --nPos );
425 if ( pData->bEnabled )
427 USHORT n = pData->aText.Search( '~' );
428 if ( n != STRING_NOTFOUND )
430 KeyCode mnKeyCode;
431 // if MapUnicodeToKeyCode fails or is unsupported we try the pure ascii mapping of the keycodes
432 // so we have working shortcuts when ascii mnemonics are used
433 Window* pDefWindow = ImplGetDefaultWindow();
434 if( (pDefWindow && pDefWindow->ImplGetFrame()->MapUnicodeToKeyCode( pData->aText.GetChar(n+1), Application::GetSettings().GetUILanguage(), mnKeyCode )
435 && aKeyCode.GetCode() == mnKeyCode.GetCode())
436 || ( ascii && rI18nHelper.MatchMnemonic( pData->aText, ascii ) ) )
437 nItems++;
442 return nItems;
445 uno::Reference< i18n::XCharacterClassification > MenuItemList::GetCharClass() const
447 if ( !xCharClass.is() )
448 ((MenuItemList*)this)->xCharClass = vcl::unohelper::CreateCharacterClassification();
449 return xCharClass;
454 // ----------------------
455 // - MenuFloatingWindow -
456 // ----------------------
458 class MenuFloatingWindow : public FloatingWindow
460 friend void Menu::ImplFillLayoutData() const;
461 friend Menu::~Menu();
463 private:
464 Menu* pMenu;
465 PopupMenu* pActivePopup;
466 Timer aHighlightChangedTimer;
467 Timer aSubmenuCloseTimer;
468 Timer aScrollTimer;
469 ULONG nSaveFocusId;
470 // long nStartY;
471 USHORT nHighlightedItem; // gehighlightetes/selektiertes Item
472 USHORT nMBDownPos;
473 USHORT nScrollerHeight;
474 USHORT nFirstEntry;
475 USHORT nBorder;
476 USHORT nPosInParent;
477 BOOL bInExecute;
479 BOOL bScrollMenu;
480 BOOL bScrollUp;
481 BOOL bScrollDown;
482 BOOL bIgnoreFirstMove;
483 BOOL bKeyInput;
485 DECL_LINK( PopupEnd, FloatingWindow* );
486 DECL_LINK( HighlightChanged, Timer* );
487 DECL_LINK( SubmenuClose, Timer* );
488 DECL_LINK( AutoScroll, Timer* );
489 DECL_LINK( ShowHideListener, VclWindowEvent* );
491 void StateChanged( StateChangedType nType );
492 void DataChanged( const DataChangedEvent& rDCEvt );
493 protected:
494 Region ImplCalcClipRegion( BOOL bIncludeLogo = TRUE ) const;
495 void ImplInitClipRegion();
496 void ImplDrawScroller( BOOL bUp );
497 using Window::ImplScroll;
498 void ImplScroll( const Point& rMousePos );
499 void ImplScroll( BOOL bUp );
500 void ImplCursorUpDown( BOOL bUp, BOOL bHomeEnd = FALSE );
501 void ImplHighlightItem( const MouseEvent& rMEvt, BOOL bMBDown );
502 long ImplGetStartY() const;
503 Rectangle ImplGetItemRect( USHORT nPos );
505 public:
506 MenuFloatingWindow( Menu* pMenu, Window* pParent, WinBits nStyle );
507 ~MenuFloatingWindow();
509 void doShutdown();
511 virtual void MouseMove( const MouseEvent& rMEvt );
512 virtual void MouseButtonDown( const MouseEvent& rMEvt );
513 virtual void MouseButtonUp( const MouseEvent& rMEvt );
514 virtual void KeyInput( const KeyEvent& rKEvent );
515 virtual void Command( const CommandEvent& rCEvt );
516 virtual void Paint( const Rectangle& rRect );
517 virtual void RequestHelp( const HelpEvent& rHEvt );
518 virtual void Resize();
520 void SetFocusId( ULONG nId ) { nSaveFocusId = nId; }
521 ULONG GetFocusId() const { return nSaveFocusId; }
523 void EnableScrollMenu( BOOL b );
524 BOOL IsScrollMenu() const { return bScrollMenu; }
525 USHORT GetScrollerHeight() const { return nScrollerHeight; }
527 void Execute();
528 void StopExecute( ULONG nFocusId = 0 );
529 void EndExecute();
530 void EndExecute( USHORT nSelectId );
532 PopupMenu* GetActivePopup() const { return pActivePopup; }
533 void KillActivePopup( PopupMenu* pThisOnly = NULL );
535 void HighlightItem( USHORT nPos, BOOL bHighlight );
536 void ChangeHighlightItem( USHORT n, BOOL bStartPopupTimer );
537 USHORT GetHighlightedItem() const { return nHighlightedItem; }
539 void SetPosInParent( USHORT nPos ) { nPosInParent = nPos; }
540 USHORT GetPosInParent() const { return nPosInParent; }
542 virtual ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible > CreateAccessible();
545 // To get the transparent mouse-over look, the closer is actually a toolbox
546 // overload DataChange to handle style changes correctly
547 class DecoToolBox : public ToolBox
549 long lastSize;
550 Size maMinSize;
552 using Window::ImplInit;
553 public:
554 DecoToolBox( Window* pParent, WinBits nStyle = 0 );
555 DecoToolBox( Window* pParent, const ResId& rResId );
556 void ImplInit();
558 void DataChanged( const DataChangedEvent& rDCEvt );
560 void SetImages( long nMaxHeight = 0 );
562 void calcMinSize();
563 Size getMinSize();
565 Image maImage;
566 Image maImageHC;
569 DecoToolBox::DecoToolBox( Window* pParent, WinBits nStyle ) :
570 ToolBox( pParent, nStyle )
572 ImplInit();
574 DecoToolBox::DecoToolBox( Window* pParent, const ResId& rResId ) :
575 ToolBox( pParent, rResId )
577 ImplInit();
580 void DecoToolBox::ImplInit()
582 lastSize = -1;
583 calcMinSize();
586 void DecoToolBox::DataChanged( const DataChangedEvent& rDCEvt )
588 Window::DataChanged( rDCEvt );
590 if ( rDCEvt.GetFlags() & SETTINGS_STYLE )
592 calcMinSize();
593 SetBackground();
594 SetImages();
598 void DecoToolBox::calcMinSize()
600 ToolBox aTbx( GetParent() );
601 if( GetItemCount() == 0 )
603 ResMgr* pResMgr = ImplGetResMgr();
605 Bitmap aBitmap;
606 if( pResMgr )
607 aBitmap = Bitmap( ResId( SV_RESID_BITMAP_CLOSEDOC, *pResMgr ) );
608 aTbx.InsertItem( IID_DOCUMENTCLOSE, Image( aBitmap ) );
610 else
612 USHORT nItems = GetItemCount();
613 for( USHORT i = 0; i < nItems; i++ )
615 USHORT nId = GetItemId( i );
616 aTbx.InsertItem( nId, GetItemImage( nId ) );
619 aTbx.SetOutStyle( TOOLBOX_STYLE_FLAT );
620 maMinSize = aTbx.CalcWindowSizePixel();
623 Size DecoToolBox::getMinSize()
625 return maMinSize;
628 void DecoToolBox::SetImages( long nMaxHeight )
630 long border = getMinSize().Height() - maImage.GetSizePixel().Height();
632 if( !nMaxHeight && lastSize != -1 )
633 nMaxHeight = lastSize + border; // don't change anything if called with 0
635 if( nMaxHeight < getMinSize().Height() )
636 nMaxHeight = getMinSize().Height();
638 if( lastSize != nMaxHeight - border )
640 lastSize = nMaxHeight - border;
642 Color aEraseColor( 255, 255, 255, 255 );
643 BitmapEx aBmpExDst( maImage.GetBitmapEx() );
644 BitmapEx aBmpExSrc( GetSettings().GetStyleSettings().GetMenuBarColor().IsDark() ?
645 maImageHC.GetBitmapEx() : aBmpExDst );
647 aEraseColor.SetTransparency( 255 );
648 aBmpExDst.Erase( aEraseColor );
649 aBmpExDst.SetSizePixel( Size( lastSize, lastSize ) );
651 Rectangle aSrcRect( Point(0,0), maImage.GetSizePixel() );
652 Rectangle aDestRect( Point((lastSize - maImage.GetSizePixel().Width())/2,
653 (lastSize - maImage.GetSizePixel().Height())/2 ),
654 maImage.GetSizePixel() );
657 aBmpExDst.CopyPixel( aDestRect, aSrcRect, &aBmpExSrc );
658 SetItemImage( IID_DOCUMENTCLOSE, Image( aBmpExDst ) );
663 // Eine Basicklasse fuer beide (wegen pActivePopup, Timer, ...) waere nett,
664 // aber dann musste eine 'Container'-Klasse gemacht werden, da von
665 // unterschiedlichen Windows abgeleitet...
666 // In den meisten Funktionen muessen dann sowieso Sonderbehandlungen fuer
667 // MenuBar, PopupMenu gemacht werden, also doch zwei verschiedene Klassen.
669 class MenuBarWindow : public Window
671 friend class MenuBar;
672 friend class Menu;
674 private:
675 struct AddButtonEntry
677 USHORT m_nId;
678 Link m_aSelectLink;
679 Link m_aHighlightLink;
681 AddButtonEntry() : m_nId( 0 ) {}
684 Menu* pMenu;
685 PopupMenu* pActivePopup;
686 USHORT nHighlightedItem;
687 ULONG nSaveFocusId;
688 BOOL mbAutoPopup;
689 BOOL bIgnoreFirstMove;
690 BOOL bStayActive;
692 DecoToolBox aCloser;
693 PushButton aFloatBtn;
694 PushButton aHideBtn;
696 std::map< USHORT, AddButtonEntry > m_aAddButtons;
698 void HighlightItem( USHORT nPos, BOOL bHighlight );
699 void ChangeHighlightItem( USHORT n, BOOL bSelectPopupEntry, BOOL bAllowRestoreFocus = TRUE, BOOL bDefaultToDocument = TRUE );
701 USHORT ImplFindEntry( const Point& rMousePos ) const;
702 void ImplCreatePopup( BOOL bPreSelectFirst );
703 BOOL ImplHandleKeyEvent( const KeyEvent& rKEvent, BOOL bFromMenu = TRUE );
704 Rectangle ImplGetItemRect( USHORT nPos );
706 void ImplInitStyleSettings();
708 DECL_LINK( CloserHdl, PushButton* );
709 DECL_LINK( FloatHdl, PushButton* );
710 DECL_LINK( HideHdl, PushButton* );
711 DECL_LINK( ToolboxEventHdl, VclWindowEvent* );
712 DECL_LINK( ShowHideListener, VclWindowEvent* );
714 void StateChanged( StateChangedType nType );
715 void DataChanged( const DataChangedEvent& rDCEvt );
716 void LoseFocus();
717 void GetFocus();
719 public:
720 MenuBarWindow( Window* pParent );
721 ~MenuBarWindow();
723 void ShowButtons( BOOL bClose, BOOL bFloat, BOOL bHide );
725 virtual void MouseMove( const MouseEvent& rMEvt );
726 virtual void MouseButtonDown( const MouseEvent& rMEvt );
727 virtual void MouseButtonUp( const MouseEvent& rMEvt );
728 virtual void KeyInput( const KeyEvent& rKEvent );
729 virtual void Paint( const Rectangle& rRect );
730 virtual void Resize();
731 virtual void RequestHelp( const HelpEvent& rHEvt );
733 void SetFocusId( ULONG nId ) { nSaveFocusId = nId; }
734 ULONG GetFocusId() const { return nSaveFocusId; }
736 void SetMenu( MenuBar* pMenu );
737 void KillActivePopup();
738 PopupMenu* GetActivePopup() const { return pActivePopup; }
739 void PopupClosed( Menu* pMenu );
740 USHORT GetHighlightedItem() const { return nHighlightedItem; }
741 virtual ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible > CreateAccessible();
743 void SetAutoPopup( BOOL bAuto ) { mbAutoPopup = bAuto; }
744 void ImplLayoutChanged();
745 Size MinCloseButtonSize();
747 // add an arbitrary button to the menubar (will appear next to closer)
748 USHORT AddMenuBarButton( const Image&, const Link&, const String&, USHORT nPos );
749 void SetMenuBarButtonHighlightHdl( USHORT nId, const Link& );
750 Rectangle GetMenuBarButtonRectPixel( USHORT nId );
751 void RemoveMenuBarButton( USHORT nId );
752 bool HandleMenuButtonEvent( USHORT i_nButtonId );
755 static void ImplAddNWFSeparator( Window *pThis, const MenubarValue& rMenubarValue )
757 // add a separator if
758 // - we have an adjacent docking area
759 // - and if toolbars would draw them as well (mbDockingAreaSeparateTB must not be set, see dockingarea.cxx)
760 if( rMenubarValue.maTopDockingAreaHeight && !ImplGetSVData()->maNWFData.mbDockingAreaSeparateTB )
762 // note: the menubar only provides the upper (dark) half of it, the rest (bright part) is drawn by the docking area
764 pThis->SetLineColor( pThis->GetSettings().GetStyleSettings().GetSeparatorColor() );
765 Point aPt;
766 Rectangle aRect( aPt, pThis->GetOutputSizePixel() );
767 pThis->DrawLine( aRect.BottomLeft(), aRect.BottomRight() );
771 static void ImplSetMenuItemData( MenuItemData* pData )
773 // Daten umsetzen
774 if ( !pData->aImage )
775 pData->eType = MENUITEM_STRING;
776 else if ( !pData->aText.Len() )
777 pData->eType = MENUITEM_IMAGE;
778 else
779 pData->eType = MENUITEM_STRINGIMAGE;
782 static ULONG ImplChangeTipTimeout( ULONG nTimeout, Window *pWindow )
784 AllSettings aAllSettings( pWindow->GetSettings() );
785 HelpSettings aHelpSettings( aAllSettings.GetHelpSettings() );
786 ULONG nRet = aHelpSettings.GetTipTimeout();
787 aHelpSettings.SetTipTimeout( nTimeout );
788 aAllSettings.SetHelpSettings( aHelpSettings );
789 pWindow->SetSettings( aAllSettings );
790 return nRet;
793 static BOOL ImplHandleHelpEvent( Window* pMenuWindow, Menu* pMenu, USHORT nHighlightedItem, const HelpEvent& rHEvt, const Rectangle &rHighlightRect )
795 if( ! pMenu )
796 return FALSE;
798 BOOL bDone = FALSE;
799 USHORT nId = 0;
801 if ( nHighlightedItem != ITEMPOS_INVALID )
803 MenuItemData* pItemData = pMenu->GetItemList()->GetDataFromPos( nHighlightedItem );
804 if ( pItemData )
805 nId = pItemData->nId;
808 if ( ( rHEvt.GetMode() & HELPMODE_BALLOON ) && pMenuWindow )
810 Point aPos;
811 if( rHEvt.KeyboardActivated() )
812 aPos = rHighlightRect.Center();
813 else
814 aPos = rHEvt.GetMousePosPixel();
816 Rectangle aRect( aPos, Size() );
817 if( pMenu->GetHelpText( nId ).Len() )
818 Help::ShowBalloon( pMenuWindow, aPos, pMenu->GetHelpText( nId ) );
819 else
821 // give user a chance to read the full filename
822 ULONG oldTimeout=ImplChangeTipTimeout( 60000, pMenuWindow );
823 // call always, even when strlen==0 to correctly remove tip
824 Help::ShowQuickHelp( pMenuWindow, aRect, pMenu->GetTipHelpText( nId ) );
825 ImplChangeTipTimeout( oldTimeout, pMenuWindow );
827 bDone = TRUE;
829 else if ( ( rHEvt.GetMode() & HELPMODE_QUICK ) && pMenuWindow )
831 Point aPos = rHEvt.GetMousePosPixel();
832 Rectangle aRect( aPos, Size() );
833 // give user a chance to read the full filename
834 ULONG oldTimeout=ImplChangeTipTimeout( 60000, pMenuWindow );
835 // call always, even when strlen==0 to correctly remove tip
836 Help::ShowQuickHelp( pMenuWindow, aRect, pMenu->GetTipHelpText( nId ) );
837 ImplChangeTipTimeout( oldTimeout, pMenuWindow );
838 bDone = TRUE;
840 else if ( rHEvt.GetMode() & (HELPMODE_CONTEXT | HELPMODE_EXTENDED) )
842 // Ist eine Hilfe in die Applikation selektiert
843 Help* pHelp = Application::GetHelp();
844 if ( pHelp )
846 // Ist eine ID vorhanden, dann Hilfe mit der ID aufrufen, sonst
847 // den Hilfe-Index
848 String aCommand = pMenu->GetItemCommand( nId );
849 ULONG nHelpId = pMenu->GetHelpId( nId );
851 if ( aCommand.Len() )
852 pHelp->Start( aCommand, NULL );
853 else if ( nHelpId )
854 pHelp->Start( nHelpId, NULL );
855 else
856 pHelp->Start( OOO_HELP_INDEX, NULL );
858 bDone = TRUE;
860 return bDone;
863 static int ImplGetTopDockingAreaHeight( Window *pWindow )
865 // find docking area that is top aligned and return its height
866 // note: dockingareas are direct children of the SystemWindow
867 int height=0;
868 BOOL bDone = FALSE;
869 if( pWindow->ImplGetFrameWindow() )
871 Window *pWin = pWindow->ImplGetFrameWindow()->GetWindow( WINDOW_FIRSTCHILD); //mpWindowImpl->mpFirstChild;
872 while( pWin && !bDone )
874 if( pWin->IsSystemWindow() )
876 pWin = pWin->GetWindow( WINDOW_FIRSTCHILD); //mpWindowImpl->mpFirstChild;
877 while( pWin && !bDone )
879 DockingAreaWindow *pDockingArea = dynamic_cast< DockingAreaWindow* >( pWin );
880 if( pDockingArea && pDockingArea->GetAlign() == WINDOWALIGN_TOP )
882 bDone = TRUE;
883 if( pDockingArea->IsVisible() )
884 height = pDockingArea->GetOutputSizePixel().Height();
886 else
887 pWin = pWin->GetWindow( WINDOW_NEXT ); //mpWindowImpl->mpNext;
891 else
892 pWin = pWin->GetWindow( WINDOW_NEXT ); //mpWindowImpl->mpNext;
895 return height;
898 Menu::Menu()
900 DBG_CTOR( Menu, NULL );
901 bIsMenuBar = FALSE;
902 ImplInit();
905 // this constructor makes sure we're creating the native menu
906 // with the correct type (ie, MenuBar vs. PopupMenu)
907 Menu::Menu( BOOL bMenubar )
909 DBG_CTOR( Menu, NULL );
910 bIsMenuBar = bMenubar;
911 ImplInit();
914 Menu::~Menu()
916 DBG_DTOR( Menu, NULL );
918 vcl::LazyDeletor<Menu>::Undelete( this );
920 ImplCallEventListeners( VCLEVENT_OBJECT_DYING, ITEMPOS_INVALID );
922 // at the window free the reference to the accessible component
923 // and make sure the MenuFloatingWindow knows about our destruction
924 if ( pWindow )
926 MenuFloatingWindow* pFloat = (MenuFloatingWindow*)pWindow;
927 if( pFloat->pMenu == this )
928 pFloat->pMenu = NULL;
929 pWindow->SetAccessible( ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible >() );
932 // dispose accessible components
933 if ( mxAccessible.is() )
935 ::com::sun::star::uno::Reference< ::com::sun::star::lang::XComponent> xComponent( mxAccessible, ::com::sun::star::uno::UNO_QUERY );
936 if ( xComponent.is() )
937 xComponent->dispose();
940 if ( nEventId )
941 Application::RemoveUserEvent( nEventId );
943 bKilled = TRUE;
945 delete pItemList;
946 delete pLogo;
947 delete mpLayoutData;
949 // Native-support: destroy SalMenu
950 ImplSetSalMenu( NULL );
953 void Menu::doLazyDelete()
955 vcl::LazyDeletor<Menu>::Delete( this );
958 void Menu::ImplInit()
960 mnHighlightedItemPos = ITEMPOS_INVALID;
961 mpSalMenu = NULL;
962 nMenuFlags = 0;
963 nDefaultItem = 0;
964 //bIsMenuBar = FALSE; // this is now set in the ctor, must not be changed here!!!
965 nSelectedId = 0;
966 pItemList = new MenuItemList;
967 pLogo = NULL;
968 pStartedFrom = NULL;
969 pWindow = NULL;
970 nEventId = 0;
971 bCanceled = FALSE;
972 bInCallback = FALSE;
973 bKilled = FALSE;
974 mpLayoutData = NULL;
976 // Native-support: returns NULL if not supported
977 mpSalMenu = ImplGetSVData()->mpDefInst->CreateMenu( bIsMenuBar );
980 Menu* Menu::ImplGetStartedFrom() const
982 return pStartedFrom;
985 void Menu::ImplLoadRes( const ResId& rResId )
987 ResMgr* pMgr = rResId.GetResMgr();
988 if( ! pMgr )
989 return;
991 rResId.SetRT( RSC_MENU );
992 GetRes( rResId );
994 ULONG nObjMask = ReadLongRes();
996 if( nObjMask & RSC_MENU_ITEMS )
998 ULONG nObjFollows = ReadLongRes();
999 // MenuItems einfuegen
1000 for( ULONG i = 0; i < nObjFollows; i++ )
1002 InsertItem( ResId( (RSHEADER_TYPE*)GetClassRes(), *pMgr ) );
1003 IncrementRes( GetObjSizeRes( (RSHEADER_TYPE*)GetClassRes() ) );
1007 if( nObjMask & RSC_MENU_TEXT )
1009 if( bIsMenuBar ) // Kein Titel im Menubar
1010 ReadStringRes();
1011 else
1012 aTitleText = ReadStringRes();
1014 if( nObjMask & RSC_MENU_DEFAULTITEMID )
1015 SetDefaultItem( sal::static_int_cast<USHORT>(ReadLongRes()) );
1018 void Menu::CreateAutoMnemonics()
1020 MnemonicGenerator aMnemonicGenerator;
1021 ULONG n;
1022 for ( n = 0; n < pItemList->Count(); n++ )
1024 MenuItemData* pData = pItemList->GetDataFromPos(n);
1025 if ( ! (pData->nBits & MIB_NOSELECT ) )
1026 aMnemonicGenerator.RegisterMnemonic( pData->aText );
1028 for ( n = 0; n < pItemList->Count(); n++ )
1030 MenuItemData* pData = pItemList->GetDataFromPos(n);
1031 if ( ! (pData->nBits & MIB_NOSELECT ) )
1032 aMnemonicGenerator.CreateMnemonic( pData->aText );
1036 void Menu::Activate()
1038 bInCallback = TRUE;
1039 ImplCallEventListeners( VCLEVENT_MENU_ACTIVATE, ITEMPOS_INVALID );
1040 if ( !aActivateHdl.Call( this ) )
1042 Menu* pStartMenu = ImplGetStartMenu();
1043 if ( pStartMenu && ( pStartMenu != this ) )
1045 pStartMenu->bInCallback = TRUE;
1046 // MT 11/01: Call EventListener here? I don't know...
1047 pStartMenu->aActivateHdl.Call( this );
1048 pStartMenu->bInCallback = FALSE;
1051 bInCallback = FALSE;
1054 void Menu::Deactivate()
1056 for ( USHORT n = (USHORT)pItemList->Count(); n; )
1058 MenuItemData* pData = pItemList->GetDataFromPos( --n );
1059 if ( pData->bIsTemporary )
1060 pItemList->Remove( n );
1063 bInCallback = TRUE;
1064 Menu* pStartMenu = ImplGetStartMenu();
1065 ImplCallEventListeners( VCLEVENT_MENU_DEACTIVATE, ITEMPOS_INVALID );
1066 if ( !aDeactivateHdl.Call( this ) )
1068 if ( pStartMenu && ( pStartMenu != this ) )
1070 pStartMenu->bInCallback = TRUE;
1071 pStartMenu->aDeactivateHdl.Call( this );
1072 pStartMenu->bInCallback = FALSE;
1075 bInCallback = FALSE;
1077 if ( this == pStartMenu )
1078 GetpApp()->HideHelpStatusText();
1081 void Menu::Highlight()
1083 Menu* pStartMenu = ImplGetStartMenu();
1084 if ( !aHighlightHdl.Call( this ) )
1086 if ( pStartMenu && ( pStartMenu != this ) )
1087 pStartMenu->aHighlightHdl.Call( this );
1090 if ( GetCurItemId() )
1091 GetpApp()->ShowHelpStatusText( GetHelpText( GetCurItemId() ) );
1094 void Menu::ImplSelect()
1096 MenuItemData* pData = GetItemList()->GetData( nSelectedId );
1097 if ( pData && (pData->nBits & MIB_AUTOCHECK) )
1099 BOOL bChecked = IsItemChecked( nSelectedId );
1100 if ( pData->nBits & MIB_RADIOCHECK )
1102 if ( !bChecked )
1103 CheckItem( nSelectedId, TRUE );
1105 else
1106 CheckItem( nSelectedId, !bChecked );
1109 // Select rufen
1110 ImplSVData* pSVData = ImplGetSVData();
1111 pSVData->maAppData.mpActivePopupMenu = NULL; // Falls neues Execute im Select()
1112 Application::PostUserEvent( nEventId, LINK( this, Menu, ImplCallSelect ) );
1115 void Menu::Select()
1117 ImplCallEventListeners( VCLEVENT_MENU_SELECT, GetItemPos( GetCurItemId() ) );
1118 if ( !aSelectHdl.Call( this ) )
1120 Menu* pStartMenu = ImplGetStartMenu();
1121 if ( pStartMenu && ( pStartMenu != this ) )
1123 pStartMenu->nSelectedId = nSelectedId;
1124 pStartMenu->aSelectHdl.Call( this );
1129 void Menu::ImplSelectWithStart( Menu* pSMenu )
1131 Menu* pOldStartedFrom = pStartedFrom;
1132 pStartedFrom = pSMenu;
1133 Menu* pOldStartedStarted = pOldStartedFrom ? pOldStartedFrom->pStartedFrom : NULL;
1134 Select();
1135 if( pOldStartedFrom )
1136 pOldStartedFrom->pStartedFrom = pOldStartedStarted;
1137 pStartedFrom = pOldStartedFrom;
1140 void Menu::RequestHelp( const HelpEvent& )
1144 void Menu::ImplCallEventListeners( ULONG nEvent, USHORT nPos )
1146 VclMenuEvent aEvent( this, nEvent, nPos );
1148 // This is needed by atk accessibility bridge
1149 if ( nEvent == VCLEVENT_MENU_HIGHLIGHT )
1151 ImplGetSVData()->mpApp->ImplCallEventListeners( &aEvent );
1154 if ( !maEventListeners.empty() )
1155 maEventListeners.Call( &aEvent );
1157 Menu* pMenu = this;
1158 while ( pMenu )
1160 if ( !maChildEventListeners.empty() )
1161 maChildEventListeners.Call( &aEvent );
1163 pMenu = ( pMenu->pStartedFrom != pMenu ) ? pMenu->pStartedFrom : NULL;
1167 void Menu::AddEventListener( const Link& rEventListener )
1169 maEventListeners.push_back( rEventListener );
1172 void Menu::RemoveEventListener( const Link& rEventListener )
1174 maEventListeners.remove( rEventListener );
1177 // -----------------------------------------------------------------------
1179 //void Menu::AddChildEventListener( const Link& rEventListener )
1181 // mpDummy4_WindowChildEventListeners->push_back( rEventListener );
1184 // -----------------------------------------------------------------------
1186 //void Menu::RemoveChildEventListener( const Link& rEventListener )
1188 // mpDummy4_WindowChildEventListeners->remove( rEventListener );
1191 void Menu::InsertItem( USHORT nItemId, const XubString& rStr, MenuItemBits nItemBits, USHORT nPos )
1193 DBG_ASSERT( nItemId, "Menu::InsertItem(): ItemId == 0" );
1194 DBG_ASSERT( GetItemPos( nItemId ) == MENU_ITEM_NOTFOUND,
1195 "Menu::InsertItem(): ItemId already exists" );
1197 // if Position > ItemCount, append
1198 if ( nPos >= (USHORT)pItemList->Count() )
1199 nPos = MENU_APPEND;
1201 // put Item in MenuItemList
1202 MenuItemData* pData = pItemList->Insert( nItemId, MENUITEM_STRING,
1203 nItemBits, rStr, Image(), this, nPos );
1205 // update native menu
1206 if( ImplGetSalMenu() && pData->pSalMenuItem )
1207 ImplGetSalMenu()->InsertItem( pData->pSalMenuItem, nPos );
1209 Window* pWin = ImplGetWindow();
1210 delete mpLayoutData, mpLayoutData = NULL;
1211 if ( pWin )
1213 ImplCalcSize( pWin );
1214 if ( pWin->IsVisible() )
1215 pWin->Invalidate();
1217 ImplCallEventListeners( VCLEVENT_MENU_INSERTITEM, nPos );
1220 void Menu::InsertItem( USHORT nItemId, const Image& rImage,
1221 MenuItemBits nItemBits, USHORT nPos )
1223 InsertItem( nItemId, ImplGetSVEmptyStr(), nItemBits, nPos );
1224 SetItemImage( nItemId, rImage );
1227 void Menu::InsertItem( USHORT nItemId,
1228 const XubString& rStr, const Image& rImage,
1229 MenuItemBits nItemBits, USHORT nPos )
1231 InsertItem( nItemId, rStr, nItemBits, nPos );
1232 SetItemImage( nItemId, rImage );
1235 void Menu::InsertItem( const ResId& rResId, USHORT nPos )
1237 ResMgr* pMgr = rResId.GetResMgr();
1238 if( ! pMgr )
1239 return;
1241 ULONG nObjMask;
1243 GetRes( rResId.SetRT( RSC_MENUITEM ) );
1244 nObjMask = ReadLongRes();
1246 BOOL bSep = FALSE;
1247 if ( nObjMask & RSC_MENUITEM_SEPARATOR )
1248 bSep = (BOOL)ReadShortRes();
1250 USHORT nItemId = 1;
1251 if ( nObjMask & RSC_MENUITEM_ID )
1252 nItemId = sal::static_int_cast<USHORT>(ReadLongRes());
1254 MenuItemBits nStatus = 0;
1255 if ( nObjMask & RSC_MENUITEM_STATUS )
1256 nStatus = sal::static_int_cast<MenuItemBits>(ReadLongRes());
1258 String aText;
1259 if ( nObjMask & RSC_MENUITEM_TEXT )
1260 aText = ReadStringRes();
1262 // Item erzeugen
1263 if ( nObjMask & RSC_MENUITEM_BITMAP )
1265 if ( !bSep )
1267 Bitmap aBmp( ResId( (RSHEADER_TYPE*)GetClassRes(), *pMgr ) );
1268 if ( aText.Len() )
1269 InsertItem( nItemId, aText, aBmp, nStatus, nPos );
1270 else
1271 InsertItem( nItemId, aBmp, nStatus, nPos );
1273 IncrementRes( GetObjSizeRes( (RSHEADER_TYPE*)GetClassRes() ) );
1275 else if ( !bSep )
1276 InsertItem( nItemId, aText, nStatus, nPos );
1277 if ( bSep )
1278 InsertSeparator( nPos );
1280 String aHelpText;
1281 if ( nObjMask & RSC_MENUITEM_HELPTEXT )
1283 aHelpText = ReadStringRes();
1284 if( !bSep )
1285 SetHelpText( nItemId, aHelpText );
1288 ULONG nHelpId = 0;
1289 if ( nObjMask & RSC_MENUITEM_HELPID )
1291 nHelpId = ReadLongRes();
1292 if ( !bSep )
1293 SetHelpId( nItemId, nHelpId );
1296 if( !bSep /* && SvHelpSettings::HelpText( aHelpText, nHelpId ) */ )
1297 SetHelpText( nItemId, aHelpText );
1299 if ( nObjMask & RSC_MENUITEM_KEYCODE )
1301 if ( !bSep )
1302 SetAccelKey( nItemId, KeyCode( ResId( (RSHEADER_TYPE*)GetClassRes(), *pMgr ) ) );
1303 IncrementRes( GetObjSizeRes( (RSHEADER_TYPE*)GetClassRes() ) );
1305 if( nObjMask & RSC_MENUITEM_CHECKED )
1307 if ( !bSep )
1308 CheckItem( nItemId, (BOOL)ReadShortRes() );
1310 if ( nObjMask & RSC_MENUITEM_DISABLE )
1312 if ( !bSep )
1313 EnableItem( nItemId, !(BOOL)ReadShortRes() );
1315 if ( nObjMask & RSC_MENUITEM_COMMAND )
1317 String aCommandStr = ReadStringRes();
1318 if ( !bSep )
1319 SetItemCommand( nItemId, aCommandStr );
1321 if ( nObjMask & RSC_MENUITEM_MENU )
1323 if ( !bSep )
1325 MenuItemData* pData = GetItemList()->GetData( nItemId );
1326 if ( pData )
1328 PopupMenu* pSubMenu = new PopupMenu( ResId( (RSHEADER_TYPE*)GetClassRes(), *pMgr ) );
1329 pData->pAutoSubMenu = pSubMenu;
1330 // #111060# keep track of this pointer, may be it will be deleted from outside
1331 pSubMenu->pRefAutoSubMenu = &pData->pAutoSubMenu;
1332 SetPopupMenu( nItemId, pSubMenu );
1335 IncrementRes( GetObjSizeRes( (RSHEADER_TYPE*)GetClassRes() ) );
1337 delete mpLayoutData, mpLayoutData = NULL;
1340 void Menu::InsertSeparator( USHORT nPos )
1342 // do nothing if its a menu bar
1343 if ( bIsMenuBar )
1344 return;
1346 // if position > ItemCount, append
1347 if ( nPos >= (USHORT)pItemList->Count() )
1348 nPos = MENU_APPEND;
1350 // put separator in item list
1351 pItemList->InsertSeparator( nPos );
1353 // update native menu
1354 USHORT itemPos = nPos != MENU_APPEND ? nPos : (USHORT)pItemList->Count() - 1;
1355 MenuItemData *pData = pItemList->GetDataFromPos( itemPos );
1356 if( ImplGetSalMenu() && pData && pData->pSalMenuItem )
1357 ImplGetSalMenu()->InsertItem( pData->pSalMenuItem, nPos );
1359 delete mpLayoutData, mpLayoutData = NULL;
1361 ImplCallEventListeners( VCLEVENT_MENU_INSERTITEM, nPos );
1364 void Menu::RemoveItem( USHORT nPos )
1366 BOOL bRemove = FALSE;
1368 if ( nPos < GetItemCount() )
1370 // update native menu
1371 if( ImplGetSalMenu() )
1372 ImplGetSalMenu()->RemoveItem( nPos );
1374 pItemList->Remove( nPos );
1375 bRemove = TRUE;
1378 Window* pWin = ImplGetWindow();
1379 if ( pWin )
1381 ImplCalcSize( pWin );
1382 if ( pWin->IsVisible() )
1383 pWin->Invalidate();
1385 delete mpLayoutData, mpLayoutData = NULL;
1387 if ( bRemove )
1388 ImplCallEventListeners( VCLEVENT_MENU_REMOVEITEM, nPos );
1391 void ImplCopyItem( Menu* pThis, const Menu& rMenu, USHORT nPos, USHORT nNewPos,
1392 USHORT nMode = 0 )
1394 MenuItemType eType = rMenu.GetItemType( nPos );
1396 if ( eType == MENUITEM_DONTKNOW )
1397 return;
1399 if ( eType == MENUITEM_SEPARATOR )
1400 pThis->InsertSeparator( nNewPos );
1401 else
1403 USHORT nId = rMenu.GetItemId( nPos );
1405 DBG_ASSERT( pThis->GetItemPos( nId ) == MENU_ITEM_NOTFOUND,
1406 "Menu::CopyItem(): ItemId already exists" );
1408 MenuItemData* pData = rMenu.GetItemList()->GetData( nId );
1410 if ( eType == MENUITEM_STRINGIMAGE )
1411 pThis->InsertItem( nId, pData->aText, pData->aImage, pData->nBits, nNewPos );
1412 else if ( eType == MENUITEM_STRING )
1413 pThis->InsertItem( nId, pData->aText, pData->nBits, nNewPos );
1414 else
1415 pThis->InsertItem( nId, pData->aImage, pData->nBits, nNewPos );
1417 if ( rMenu.IsItemChecked( nId ) )
1418 pThis->CheckItem( nId, TRUE );
1419 if ( !rMenu.IsItemEnabled( nId ) )
1420 pThis->EnableItem( nId, FALSE );
1421 pThis->SetHelpId( nId, pData->nHelpId );
1422 pThis->SetHelpText( nId, pData->aHelpText );
1423 pThis->SetAccelKey( nId, pData->aAccelKey );
1424 pThis->SetItemCommand( nId, pData->aCommandStr );
1425 pThis->SetHelpCommand( nId, pData->aHelpCommandStr );
1427 PopupMenu* pSubMenu = rMenu.GetPopupMenu( nId );
1428 if ( pSubMenu )
1430 // AutoKopie anlegen
1431 if ( nMode == 1 )
1433 PopupMenu* pNewMenu = new PopupMenu( *pSubMenu );
1434 pThis->SetPopupMenu( nId, pNewMenu );
1435 // SetAutoMenu( pThis, nId, pNewMenu );
1437 else
1438 pThis->SetPopupMenu( nId, pSubMenu );
1443 void Menu::CopyItem( const Menu& rMenu, USHORT nPos, USHORT nNewPos )
1445 ImplCopyItem( this, rMenu, nPos, nNewPos );
1448 void Menu::Clear()
1450 for ( USHORT i = GetItemCount(); i; i-- )
1451 RemoveItem( 0 );
1454 USHORT Menu::GetItemCount() const
1456 return (USHORT)pItemList->Count();
1459 USHORT Menu::ImplGetVisibleItemCount() const
1461 USHORT nItems = 0;
1462 for ( USHORT n = (USHORT)pItemList->Count(); n; )
1464 if ( ImplIsVisible( --n ) )
1465 nItems++;
1467 return nItems;
1470 USHORT Menu::ImplGetFirstVisible() const
1472 for ( USHORT n = 0; n < pItemList->Count(); n++ )
1474 if ( ImplIsVisible( n ) )
1475 return n;
1477 return ITEMPOS_INVALID;
1480 USHORT Menu::ImplGetPrevVisible( USHORT nPos ) const
1482 for ( USHORT n = nPos; n; )
1484 if ( n && ImplIsVisible( --n ) )
1485 return n;
1487 return ITEMPOS_INVALID;
1490 USHORT Menu::ImplGetNextVisible( USHORT nPos ) const
1492 for ( USHORT n = nPos+1; n < pItemList->Count(); n++ )
1494 if ( ImplIsVisible( n ) )
1495 return n;
1497 return ITEMPOS_INVALID;
1500 USHORT Menu::GetItemId( USHORT nPos ) const
1502 MenuItemData* pData = pItemList->GetDataFromPos( nPos );
1504 if ( pData )
1505 return pData->nId;
1506 else
1507 return 0;
1510 USHORT Menu::GetItemPos( USHORT nItemId ) const
1512 USHORT nPos;
1513 MenuItemData* pData = pItemList->GetData( nItemId, nPos );
1515 if ( pData )
1516 return nPos;
1517 else
1518 return MENU_ITEM_NOTFOUND;
1521 MenuItemType Menu::GetItemType( USHORT nPos ) const
1523 MenuItemData* pData = pItemList->GetDataFromPos( nPos );
1525 if ( pData )
1526 return pData->eType;
1527 else
1528 return MENUITEM_DONTKNOW;
1531 USHORT Menu::GetCurItemId() const
1533 return nSelectedId;
1536 void Menu::SetItemBits( USHORT nItemId, MenuItemBits nBits )
1538 MenuItemData* pData = pItemList->GetData( nItemId );
1539 if ( pData )
1540 pData->nBits = nBits;
1543 MenuItemBits Menu::GetItemBits( USHORT nItemId ) const
1545 MenuItemBits nBits = 0;
1546 MenuItemData* pData = pItemList->GetData( nItemId );
1547 if ( pData )
1548 nBits = pData->nBits;
1549 return nBits;
1552 void Menu::SetUserValue( USHORT nItemId, ULONG nValue )
1554 MenuItemData* pData = pItemList->GetData( nItemId );
1555 if ( pData )
1556 pData->nUserValue = nValue;
1559 ULONG Menu::GetUserValue( USHORT nItemId ) const
1561 MenuItemData* pData = pItemList->GetData( nItemId );
1562 return pData ? pData->nUserValue : 0;
1565 void Menu::SetPopupMenu( USHORT nItemId, PopupMenu* pMenu )
1567 USHORT nPos;
1568 MenuItemData* pData = pItemList->GetData( nItemId, nPos );
1570 // Item does not exist -> return NULL
1571 if ( !pData )
1572 return;
1574 // same menu, nothing to do
1575 if ( (PopupMenu*)pData->pSubMenu == pMenu )
1576 return;
1578 // data exchange
1579 pData->pSubMenu = pMenu;
1581 // #112023# Make sure pStartedFrom does not point to invalid (old) data
1582 if ( pData->pSubMenu )
1583 pData->pSubMenu->pStartedFrom = 0;
1585 // set native submenu
1586 if( ImplGetSalMenu() && pData->pSalMenuItem )
1588 if( pMenu )
1589 ImplGetSalMenu()->SetSubMenu( pData->pSalMenuItem, pMenu->ImplGetSalMenu(), nPos );
1590 else
1591 ImplGetSalMenu()->SetSubMenu( pData->pSalMenuItem, NULL, nPos );
1594 ImplCallEventListeners( VCLEVENT_MENU_SUBMENUCHANGED, nPos );
1597 PopupMenu* Menu::GetPopupMenu( USHORT nItemId ) const
1599 MenuItemData* pData = pItemList->GetData( nItemId );
1601 if ( pData )
1602 return (PopupMenu*)(pData->pSubMenu);
1603 else
1604 return NULL;
1607 void Menu::SetAccelKey( USHORT nItemId, const KeyCode& rKeyCode )
1609 USHORT nPos;
1610 MenuItemData* pData = pItemList->GetData( nItemId, nPos );
1612 if ( !pData )
1613 return;
1615 if ( pData->aAccelKey == rKeyCode )
1616 return;
1618 pData->aAccelKey = rKeyCode;
1620 // update native menu
1621 if( ImplGetSalMenu() && pData->pSalMenuItem )
1622 ImplGetSalMenu()->SetAccelerator( nPos, pData->pSalMenuItem, rKeyCode, rKeyCode.GetName() );
1625 KeyCode Menu::GetAccelKey( USHORT nItemId ) const
1627 MenuItemData* pData = pItemList->GetData( nItemId );
1629 if ( pData )
1630 return pData->aAccelKey;
1631 else
1632 return KeyCode();
1635 KeyEvent Menu::GetActivationKey( USHORT nItemId ) const
1637 KeyEvent aRet;
1638 MenuItemData* pData = pItemList->GetData( nItemId );
1639 if( pData )
1641 USHORT nPos = pData->aText.Search( '~' );
1642 if( nPos != STRING_NOTFOUND && nPos < pData->aText.Len()-1 )
1644 USHORT nCode = 0;
1645 sal_Unicode cAccel = pData->aText.GetChar( nPos+1 );
1646 if( cAccel >= 'a' && cAccel <= 'z' )
1647 nCode = KEY_A + (cAccel-'a');
1648 else if( cAccel >= 'A' && cAccel <= 'Z' )
1649 nCode = KEY_A + (cAccel-'A');
1650 else if( cAccel >= '0' && cAccel <= '9' )
1651 nCode = KEY_0 + (cAccel-'0');
1652 if(nCode )
1653 aRet = KeyEvent( cAccel, KeyCode( nCode, KEY_MOD2 ) );
1657 return aRet;
1660 void Menu::CheckItem( USHORT nItemId, BOOL bCheck )
1662 USHORT nPos;
1663 MenuItemData* pData = pItemList->GetData( nItemId, nPos );
1665 if ( !pData || pData->bChecked == bCheck )
1666 return;
1668 // Wenn RadioCheck, dann vorherigen unchecken
1669 if ( bCheck && (pData->nBits & MIB_AUTOCHECK) &&
1670 (pData->nBits & MIB_RADIOCHECK) )
1672 MenuItemData* pGroupData;
1673 USHORT nGroupPos;
1674 USHORT nItemCount = GetItemCount();
1675 BOOL bFound = FALSE;
1677 nGroupPos = nPos;
1678 while ( nGroupPos )
1680 pGroupData = pItemList->GetDataFromPos( nGroupPos-1 );
1681 if ( pGroupData->nBits & MIB_RADIOCHECK )
1683 if ( IsItemChecked( pGroupData->nId ) )
1685 CheckItem( pGroupData->nId, FALSE );
1686 bFound = TRUE;
1687 break;
1690 else
1691 break;
1692 nGroupPos--;
1695 if ( !bFound )
1697 nGroupPos = nPos+1;
1698 while ( nGroupPos < nItemCount )
1700 pGroupData = pItemList->GetDataFromPos( nGroupPos );
1701 if ( pGroupData->nBits & MIB_RADIOCHECK )
1703 if ( IsItemChecked( pGroupData->nId ) )
1705 CheckItem( pGroupData->nId, FALSE );
1706 break;
1709 else
1710 break;
1711 nGroupPos++;
1716 pData->bChecked = bCheck;
1718 // update native menu
1719 if( ImplGetSalMenu() )
1720 ImplGetSalMenu()->CheckItem( nPos, bCheck );
1722 ImplCallEventListeners( bCheck ? VCLEVENT_MENU_ITEMCHECKED : VCLEVENT_MENU_ITEMUNCHECKED, nPos );
1725 BOOL Menu::IsItemChecked( USHORT nItemId ) const
1727 USHORT nPos;
1728 MenuItemData* pData = pItemList->GetData( nItemId, nPos );
1730 if ( !pData )
1731 return FALSE;
1733 return pData->bChecked;
1736 void Menu::EnableItem( USHORT nItemId, BOOL bEnable )
1738 USHORT nPos;
1739 MenuItemData* pItemData = pItemList->GetData( nItemId, nPos );
1741 if ( pItemData && ( pItemData->bEnabled != bEnable ) )
1743 pItemData->bEnabled = bEnable;
1745 Window* pWin = ImplGetWindow();
1746 if ( pWin && pWin->IsVisible() )
1748 DBG_ASSERT( bIsMenuBar, "Menu::EnableItem - Popup visible!" );
1749 long nX = 0;
1750 ULONG nCount = pItemList->Count();
1751 for ( ULONG n = 0; n < nCount; n++ )
1753 MenuItemData* pData = pItemList->GetDataFromPos( n );
1754 if ( n == nPos )
1756 pWin->Invalidate( Rectangle( Point( nX, 0 ), Size( pData->aSz.Width(), pData->aSz.Height() ) ) );
1757 break;
1759 nX += pData->aSz.Width();
1762 // update native menu
1763 if( ImplGetSalMenu() )
1764 ImplGetSalMenu()->EnableItem( nPos, bEnable );
1766 ImplCallEventListeners( bEnable ? VCLEVENT_MENU_ENABLE : VCLEVENT_MENU_DISABLE, nPos );
1770 BOOL Menu::IsItemEnabled( USHORT nItemId ) const
1772 USHORT nPos;
1773 MenuItemData* pData = pItemList->GetData( nItemId, nPos );
1775 if ( !pData )
1776 return FALSE;
1778 return pData->bEnabled;
1781 void Menu::ShowItem( USHORT nItemId, BOOL bVisible )
1783 USHORT nPos;
1784 MenuItemData* pData = pItemList->GetData( nItemId, nPos );
1786 DBG_ASSERT( !bIsMenuBar, "Menu::ShowItem - ignored for menu bar entries!" );
1787 if ( !bIsMenuBar && pData && ( pData->bVisible != bVisible ) )
1789 Window* pWin = ImplGetWindow();
1790 if ( pWin && pWin->IsVisible() )
1792 DBG_ASSERT( 0, "Menu::ShowItem - ignored for visible popups!" );
1793 return;
1795 pData->bVisible = bVisible;
1797 // update native menu
1798 // as long as there is no support to hide native menu entries, we just disable them
1799 // TODO: add support to show/hide native menu entries
1800 if( ImplGetSalMenu() )
1801 ImplGetSalMenu()->EnableItem( nPos, bVisible );
1805 void Menu::SetItemText( USHORT nItemId, const XubString& rStr )
1807 USHORT nPos;
1808 MenuItemData* pData = pItemList->GetData( nItemId, nPos );
1810 if ( !pData )
1811 return;
1813 if ( !rStr.Equals( pData->aText ) )
1815 pData->aText = rStr;
1816 ImplSetMenuItemData( pData );
1817 // update native menu
1818 if( ImplGetSalMenu() && pData->pSalMenuItem )
1819 ImplGetSalMenu()->SetItemText( nPos, pData->pSalMenuItem, rStr );
1821 Window* pWin = ImplGetWindow();
1822 delete mpLayoutData, mpLayoutData = NULL;
1823 if ( pWin && IsMenuBar() )
1825 ImplCalcSize( pWin );
1826 if ( pWin->IsVisible() )
1827 pWin->Invalidate();
1830 ImplCallEventListeners( VCLEVENT_MENU_ITEMTEXTCHANGED, nPos );
1834 XubString Menu::GetItemText( USHORT nItemId ) const
1836 USHORT nPos;
1837 MenuItemData* pData = pItemList->GetData( nItemId, nPos );
1839 if ( pData )
1840 return pData->aText;
1841 else
1842 return ImplGetSVEmptyStr();
1845 void Menu::SetItemImage( USHORT nItemId, const Image& rImage )
1847 USHORT nPos;
1848 MenuItemData* pData = pItemList->GetData( nItemId, nPos );
1850 if ( !pData )
1851 return;
1853 pData->aImage = rImage;
1854 ImplSetMenuItemData( pData );
1856 // update native menu
1857 if( ImplGetSalMenu() && pData->pSalMenuItem )
1858 ImplGetSalMenu()->SetItemImage( nPos, pData->pSalMenuItem, rImage );
1861 static inline Image ImplRotImage( const Image& rImage, long nAngle10 )
1863 Image aRet;
1864 BitmapEx aBmpEx( rImage.GetBitmapEx() );
1866 aBmpEx.Rotate( nAngle10, COL_WHITE );
1868 return Image( aBmpEx );
1871 void Menu::SetItemImageAngle( USHORT nItemId, long nAngle10 )
1873 USHORT nPos;
1874 MenuItemData* pData = pItemList->GetData( nItemId, nPos );
1876 if ( pData )
1878 long nDeltaAngle = (nAngle10 - pData->nItemImageAngle) % 3600;
1879 while( nDeltaAngle < 0 )
1880 nDeltaAngle += 3600;
1882 pData->nItemImageAngle = nAngle10;
1883 if( nDeltaAngle && !!pData->aImage )
1884 pData->aImage = ImplRotImage( pData->aImage, nDeltaAngle );
1888 static inline Image ImplMirrorImage( const Image& rImage )
1890 Image aRet;
1891 BitmapEx aBmpEx( rImage.GetBitmapEx() );
1893 aBmpEx.Mirror( BMP_MIRROR_HORZ );
1895 return Image( aBmpEx );
1898 void Menu::SetItemImageMirrorMode( USHORT nItemId, BOOL bMirror )
1900 USHORT nPos;
1901 MenuItemData* pData = pItemList->GetData( nItemId, nPos );
1903 if ( pData )
1905 if( ( pData->bMirrorMode && ! bMirror ) ||
1906 ( ! pData->bMirrorMode && bMirror )
1909 pData->bMirrorMode = bMirror ? true : false;
1910 if( !!pData->aImage )
1911 pData->aImage = ImplMirrorImage( pData->aImage );
1916 Image Menu::GetItemImage( USHORT nItemId ) const
1918 MenuItemData* pData = pItemList->GetData( nItemId );
1920 if ( pData )
1921 return pData->aImage;
1922 else
1923 return Image();
1926 long Menu::GetItemImageAngle( USHORT nItemId ) const
1928 MenuItemData* pData = pItemList->GetData( nItemId );
1930 if ( pData )
1931 return pData->nItemImageAngle;
1932 else
1933 return 0;
1936 BOOL Menu::GetItemImageMirrorMode( USHORT nItemId ) const
1938 MenuItemData* pData = pItemList->GetData( nItemId );
1940 if ( pData )
1941 return pData->bMirrorMode;
1942 else
1943 return FALSE;
1946 void Menu::SetItemCommand( USHORT nItemId, const String& rCommand )
1948 MenuItemData* pData = pItemList->GetData( nItemId );
1950 if ( pData )
1951 pData->aCommandStr = rCommand;
1954 const XubString& Menu::GetItemCommand( USHORT nItemId ) const
1956 MenuItemData* pData = pItemList->GetData( nItemId );
1958 if ( pData )
1959 return pData->aCommandStr;
1960 else
1961 return ImplGetSVEmptyStr();
1964 void Menu::SetHelpCommand( USHORT nItemId, const XubString& rStr )
1966 MenuItemData* pData = pItemList->GetData( nItemId );
1968 if ( pData )
1969 pData->aHelpCommandStr = rStr;
1972 const XubString& Menu::GetHelpCommand( USHORT nItemId ) const
1974 MenuItemData* pData = pItemList->GetData( nItemId );
1976 if ( pData )
1977 return pData->aHelpCommandStr;
1978 else
1979 return ImplGetSVEmptyStr();
1982 void Menu::SetHelpText( USHORT nItemId, const XubString& rStr )
1984 MenuItemData* pData = pItemList->GetData( nItemId );
1986 if ( pData )
1987 pData->aHelpText = rStr;
1990 const XubString& Menu::ImplGetHelpText( USHORT nItemId ) const
1992 MenuItemData* pData = pItemList->GetData( nItemId );
1994 if ( pData )
1996 if ( !pData->aHelpText.Len() &&
1997 (( pData->nHelpId ) || ( pData->aCommandStr.Len() )))
1999 Help* pHelp = Application::GetHelp();
2000 if ( pHelp )
2002 if ( pData->aCommandStr.Len() )
2003 pData->aHelpText = pHelp->GetHelpText( pData->aCommandStr, NULL );
2005 if( !pData->aHelpText.Len() && pData->nHelpId )
2006 pData->aHelpText = pHelp->GetHelpText( pData->nHelpId, NULL );
2010 return pData->aHelpText;
2012 else
2013 return ImplGetSVEmptyStr();
2016 const XubString& Menu::GetHelpText( USHORT nItemId ) const
2018 return ImplGetHelpText( nItemId );
2021 void Menu::SetTipHelpText( USHORT nItemId, const XubString& rStr )
2023 MenuItemData* pData = pItemList->GetData( nItemId );
2025 if ( pData )
2026 pData->aTipHelpText = rStr;
2029 const XubString& Menu::GetTipHelpText( USHORT nItemId ) const
2031 MenuItemData* pData = pItemList->GetData( nItemId );
2033 if ( pData )
2034 return pData->aTipHelpText;
2035 else
2036 return ImplGetSVEmptyStr();
2039 void Menu::SetHelpId( USHORT nItemId, ULONG nHelpId )
2041 MenuItemData* pData = pItemList->GetData( nItemId );
2043 if ( pData )
2044 pData->nHelpId = nHelpId;
2047 ULONG Menu::GetHelpId( USHORT nItemId ) const
2049 MenuItemData* pData = pItemList->GetData( nItemId );
2051 if ( pData )
2052 return pData->nHelpId;
2053 else
2054 return 0;
2057 Menu& Menu::operator=( const Menu& rMenu )
2059 // Aufraeumen
2060 Clear();
2062 // Items kopieren
2063 USHORT nCount = rMenu.GetItemCount();
2064 for ( USHORT i = 0; i < nCount; i++ )
2065 ImplCopyItem( this, rMenu, i, MENU_APPEND, 1 );
2067 nDefaultItem = rMenu.nDefaultItem;
2068 aActivateHdl = rMenu.aActivateHdl;
2069 aDeactivateHdl = rMenu.aDeactivateHdl;
2070 aHighlightHdl = rMenu.aHighlightHdl;
2071 aSelectHdl = rMenu.aSelectHdl;
2072 aTitleText = rMenu.aTitleText;
2073 bIsMenuBar = rMenu.bIsMenuBar;
2075 return *this;
2078 BOOL Menu::ImplIsVisible( USHORT nPos ) const
2080 BOOL bVisible = TRUE;
2082 MenuItemData* pData = pItemList->GetDataFromPos( nPos );
2083 // check general visibility first
2084 if( pData && !pData->bVisible )
2085 bVisible = FALSE;
2087 if ( bVisible && pData && pData->eType == MENUITEM_SEPARATOR )
2089 if( nPos == 0 ) // no separator should be shown at the very beginning
2090 bVisible = FALSE;
2091 else
2093 // always avoid adjacent separators
2094 USHORT nCount = (USHORT) pItemList->Count();
2095 USHORT n;
2096 MenuItemData* pNextData = NULL;
2097 // search next visible item
2098 for( n = nPos + 1; n < nCount; n++ )
2100 pNextData = pItemList->GetDataFromPos( n );
2101 if( pNextData && pNextData->bVisible )
2103 if( pNextData->eType == MENUITEM_SEPARATOR || ImplIsVisible(n) )
2104 break;
2107 if( n == nCount ) // no next visible item
2108 bVisible = FALSE;
2109 // check for separator
2110 if( pNextData && pNextData->bVisible && pNextData->eType == MENUITEM_SEPARATOR )
2111 bVisible = FALSE;
2113 if( bVisible )
2115 for( n = nPos; n > 0; n-- )
2117 pNextData = pItemList->GetDataFromPos( n-1 );
2118 if( pNextData && pNextData->bVisible )
2120 if( pNextData->eType != MENUITEM_SEPARATOR && ImplIsVisible(n-1) )
2121 break;
2124 if( n == 0 ) // no previous visible item
2125 bVisible = FALSE;
2130 // Fuer den Menubar nicht erlaubt, weil ich nicht mitbekomme
2131 // ob dadurch ein Eintrag verschwindet oder wieder da ist.
2132 if ( bVisible && !bIsMenuBar && ( nMenuFlags & MENU_FLAG_HIDEDISABLEDENTRIES ) &&
2133 !( nMenuFlags & MENU_FLAG_ALWAYSSHOWDISABLEDENTRIES ) )
2135 if( !pData ) // e.g. nPos == ITEMPOS_INVALID
2136 bVisible = FALSE;
2137 else if ( pData->eType != MENUITEM_SEPARATOR ) // separators handled above
2139 // bVisible = pData->bEnabled && ( !pData->pSubMenu || pData->pSubMenu->HasValidEntries( TRUE ) );
2140 bVisible = pData->bEnabled; // SubMenus nicht pruefen, weil sie ggf. erst im Activate() gefuellt werden.
2144 return bVisible;
2147 BOOL Menu::IsItemVisible( USHORT nItemId ) const
2149 return IsMenuVisible() && ImplIsVisible( GetItemPos( nItemId ) );
2152 BOOL Menu::IsItemPosVisible( USHORT nItemPos ) const
2154 return IsMenuVisible() && ImplIsVisible( nItemPos );
2157 BOOL Menu::IsMenuVisible() const
2159 return pWindow && pWindow->IsReallyVisible();
2162 BOOL Menu::ImplIsSelectable( USHORT nPos ) const
2164 BOOL bSelectable = TRUE;
2166 MenuItemData* pData = pItemList->GetDataFromPos( nPos );
2167 // check general visibility first
2168 if ( pData && ( pData->nBits & MIB_NOSELECT ) )
2169 bSelectable = FALSE;
2171 return bSelectable;
2174 void Menu::SelectItem( USHORT nItemId )
2176 if( bIsMenuBar )
2177 static_cast<MenuBar*>(this)->SelectEntry( nItemId );
2178 else
2179 static_cast<PopupMenu*>(this)->SelectEntry( nItemId );
2182 ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible > Menu::GetAccessible()
2184 // Since PopupMenu are sometimes shared by different instances of MenuBar, the mxAccessible member gets
2185 // overwritten and may contain a disposed object when the initial menubar gets set again. So use the
2186 // mxAccessible member only for sub menus.
2187 if ( pStartedFrom )
2189 for ( sal_uInt16 i = 0, nCount = pStartedFrom->GetItemCount(); i < nCount; ++i )
2191 sal_uInt16 nItemId = pStartedFrom->GetItemId( i );
2192 if ( static_cast< Menu* >( pStartedFrom->GetPopupMenu( nItemId ) ) == this )
2194 ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible > xParent = pStartedFrom->GetAccessible();
2195 if ( xParent.is() )
2197 ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessibleContext > xParentContext( xParent->getAccessibleContext() );
2198 if ( xParentContext.is() )
2199 return xParentContext->getAccessibleChild( i );
2204 else if ( !mxAccessible.is() )
2206 UnoWrapperBase* pWrapper = Application::GetUnoWrapper();
2207 if ( pWrapper )
2208 mxAccessible = pWrapper->CreateAccessible( this, bIsMenuBar );
2211 return mxAccessible;
2214 void Menu::SetAccessible( const ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible >& rxAccessible )
2216 mxAccessible = rxAccessible;
2219 long Menu::ImplGetNativeCheckAndRadioSize( Window* pWin, long& rCheckHeight, long& rRadioHeight, long &rMaxWidth ) const
2221 rMaxWidth = rCheckHeight = rRadioHeight = 0;
2223 if( ! bIsMenuBar )
2225 ImplControlValue aVal;
2226 Region aNativeBounds;
2227 Region aNativeContent;
2228 Point tmp( 0, 0 );
2229 Region aCtrlRegion( Rectangle( tmp, Size( 100, 15 ) ) );
2230 if( pWin->IsNativeControlSupported( CTRL_MENU_POPUP, PART_MENU_ITEM_CHECK_MARK ) )
2232 if( pWin->GetNativeControlRegion( ControlType(CTRL_MENU_POPUP),
2233 ControlPart(PART_MENU_ITEM_CHECK_MARK),
2234 aCtrlRegion,
2235 ControlState(CTRL_STATE_ENABLED),
2236 aVal,
2237 OUString(),
2238 aNativeBounds,
2239 aNativeContent )
2242 rCheckHeight = aNativeBounds.GetBoundRect().GetHeight();
2243 rMaxWidth = aNativeContent.GetBoundRect().GetWidth();
2246 if( pWin->IsNativeControlSupported( CTRL_MENU_POPUP, PART_MENU_ITEM_RADIO_MARK ) )
2248 if( pWin->GetNativeControlRegion( ControlType(CTRL_MENU_POPUP),
2249 ControlPart(PART_MENU_ITEM_RADIO_MARK),
2250 aCtrlRegion,
2251 ControlState(CTRL_STATE_ENABLED),
2252 aVal,
2253 OUString(),
2254 aNativeBounds,
2255 aNativeContent )
2258 rRadioHeight = aNativeBounds.GetBoundRect().GetHeight();
2259 rMaxWidth = Max (rMaxWidth, aNativeContent.GetBoundRect().GetWidth());
2263 return (rCheckHeight > rRadioHeight) ? rCheckHeight : rRadioHeight;
2266 Size Menu::ImplCalcSize( Window* pWin )
2268 // | Checked| Image| Text| Accel/Popup|
2270 // Fuer Symbole: nFontHeight x nFontHeight
2271 long nFontHeight = pWin->GetTextHeight();
2272 long nExtra = nFontHeight/4;
2275 Size aSz;
2276 Size aMaxImgSz;
2277 long nMaxWidth = 0;
2278 long nMinMenuItemHeight = nFontHeight;
2279 long nCheckHeight = 0, nRadioHeight = 0;
2280 long nCheckWidth = 0, nMaxCheckWidth = 0;
2281 long nMax = ImplGetNativeCheckAndRadioSize( pWin, nCheckHeight, nRadioHeight, nMaxCheckWidth );
2282 if( nMax > nMinMenuItemHeight )
2283 nMinMenuItemHeight = nMax;
2285 // When no native rendering of the checkbox & no image in the menu, we
2286 // have to add some extra space even in the MENU_FLAG_SHOWCHECKIMAGES case
2287 bool bSpaceForCheckbox = ( nMax == 0 );
2289 const StyleSettings& rSettings = pWin->GetSettings().GetStyleSettings();
2290 if ( rSettings.GetUseImagesInMenus() )
2292 nMinMenuItemHeight = 16;
2293 for ( USHORT i = (USHORT)pItemList->Count(); i; )
2295 MenuItemData* pData = pItemList->GetDataFromPos( --i );
2296 if ( ImplIsVisible( i ) && (( pData->eType == MENUITEM_IMAGE ) || ( pData->eType == MENUITEM_STRINGIMAGE )))
2298 // we have an icon, don't add the extra space
2299 bSpaceForCheckbox = false;
2301 Size aImgSz = pData->aImage.GetSizePixel();
2302 if ( aImgSz.Height() > aMaxImgSz.Height() )
2303 aMaxImgSz.Height() = aImgSz.Height();
2304 if ( aImgSz.Height() > nMinMenuItemHeight )
2305 nMinMenuItemHeight = aImgSz.Height();
2306 break;
2311 for ( USHORT n = (USHORT)pItemList->Count(); n; )
2313 MenuItemData* pData = pItemList->GetDataFromPos( --n );
2315 pData->aSz.Height() = 0;
2316 pData->aSz.Width() = 0;
2318 if ( ImplIsVisible( n ) )
2320 long nWidth = 0;
2322 // Separator
2323 if ( !bIsMenuBar && ( pData->eType == MENUITEM_SEPARATOR ) )
2325 DBG_ASSERT( !bIsMenuBar, "Separator in MenuBar ?! " );
2326 pData->aSz.Height() = 4;
2329 // Image:
2330 if ( !bIsMenuBar && ( ( pData->eType == MENUITEM_IMAGE ) || ( pData->eType == MENUITEM_STRINGIMAGE ) ) )
2332 Size aImgSz = pData->aImage.GetSizePixel();
2333 aImgSz.Height() += 4; // add a border for native marks
2334 aImgSz.Width() += 4; // add a border for native marks
2335 if ( aImgSz.Width() > aMaxImgSz.Width() )
2336 aMaxImgSz.Width() = aImgSz.Width();
2337 if ( aImgSz.Height() > aMaxImgSz.Height() )
2338 aMaxImgSz.Height() = aImgSz.Height();
2339 if ( aImgSz.Height() > pData->aSz.Height() )
2340 pData->aSz.Height() = aImgSz.Height();
2343 // Check Buttons:
2344 if ( !bIsMenuBar && pData->HasCheck() )
2346 nCheckWidth = nMaxCheckWidth;
2347 if ( ( nMenuFlags & MENU_FLAG_SHOWCHECKIMAGES ) || bSpaceForCheckbox )
2349 // checks / images take the same place
2350 if( ! ( ( pData->eType == MENUITEM_IMAGE ) || ( pData->eType == MENUITEM_STRINGIMAGE ) ) )
2351 nWidth += nCheckWidth + nExtra * 2;
2355 // Text:
2356 if ( (pData->eType == MENUITEM_STRING) || (pData->eType == MENUITEM_STRINGIMAGE) )
2358 long nTextWidth = pWin->GetCtrlTextWidth( pData->aText );
2359 long nTextHeight = pWin->GetTextHeight();
2361 // if ( nTextHeight > pData->aSz.Height() )
2362 // pData->aSz.Height() = nTextHeight;
2364 if ( bIsMenuBar )
2366 if ( nTextHeight > pData->aSz.Height() )
2367 pData->aSz.Height() = nTextHeight;
2369 pData->aSz.Width() = nTextWidth + 4*nExtra;
2370 aSz.Width() += pData->aSz.Width();
2372 else
2373 pData->aSz.Height() = Max( Max( nTextHeight, pData->aSz.Height() ), nMinMenuItemHeight );
2375 nWidth += nTextWidth;
2378 // Accel
2379 if ( !bIsMenuBar && pData->aAccelKey.GetCode() && !ImplAccelDisabled() )
2381 String aName = pData->aAccelKey.GetName();
2382 long nAccWidth = pWin->GetTextWidth( aName );
2383 nAccWidth += nExtra;
2384 nWidth += nAccWidth;
2387 // SubMenu?
2388 if ( !bIsMenuBar && pData->pSubMenu )
2390 if ( nFontHeight > nWidth )
2391 nWidth += nFontHeight;
2393 pData->aSz.Height() = Max( Max( nFontHeight, pData->aSz.Height() ), nMinMenuItemHeight );
2396 pData->aSz.Height() += EXTRAITEMHEIGHT; // Etwas mehr Abstand:
2398 if ( !bIsMenuBar )
2399 aSz.Height() += (long)pData->aSz.Height();
2401 if ( nWidth > nMaxWidth )
2402 nMaxWidth = nWidth;
2407 if ( !bIsMenuBar )
2409 USHORT gfxExtra = (USHORT) Max( nExtra, 7L ); // #107710# increase space between checkmarks/images/text
2410 nCheckPos = (USHORT)nExtra;
2411 if ( ( nMenuFlags & MENU_FLAG_SHOWCHECKIMAGES ) || bSpaceForCheckbox )
2413 long nImgOrChkWidth = 0;
2414 nImagePos = nCheckPos;
2415 if( nMax > 0 ) // NWF case
2416 nImgOrChkWidth = nMax + nExtra;
2417 else // non NWF case
2418 nImgOrChkWidth = nFontHeight/2 + gfxExtra;
2419 nImgOrChkWidth = Max( nImgOrChkWidth, aMaxImgSz.Width() + gfxExtra );
2420 nTextPos = (USHORT)(nImagePos + nImgOrChkWidth);
2422 else
2424 nImagePos = nCheckPos;
2425 nTextPos = (USHORT)(nImagePos + Max( aMaxImgSz.Width(), nCheckWidth ));
2427 nTextPos = nTextPos + gfxExtra;
2429 aSz.Width() = nTextPos + nMaxWidth + nExtra;
2430 aSz.Width() += 4*nExtra; // a _little_ more ...
2432 int nOuterSpace = ImplGetSVData()->maNWFData.mnMenuFormatExtraBorder;
2433 aSz.Width() += 2*nOuterSpace;
2434 aSz.Height() += 2*nOuterSpace;
2436 else
2438 nTextPos = (USHORT)(2*nExtra);
2439 aSz.Height() = nFontHeight+6;
2441 // get menubar height from native methods if supported
2442 if( pWindow->IsNativeControlSupported( CTRL_MENUBAR, PART_ENTIRE_CONTROL ) )
2444 ImplControlValue aVal;
2445 Region aNativeBounds;
2446 Region aNativeContent;
2447 Point tmp( 0, 0 );
2448 Region aCtrlRegion( Rectangle( tmp, Size( 100, 15 ) ) );
2449 if( pWindow->GetNativeControlRegion( ControlType(CTRL_MENUBAR),
2450 ControlPart(PART_ENTIRE_CONTROL),
2451 aCtrlRegion,
2452 ControlState(CTRL_STATE_ENABLED),
2453 aVal,
2454 OUString(),
2455 aNativeBounds,
2456 aNativeContent )
2459 int nNativeHeight = aNativeBounds.GetBoundRect().GetHeight();
2460 if( nNativeHeight > aSz.Height() )
2461 aSz.Height() = nNativeHeight;
2465 // account for the size of the close button, which actually is a toolbox
2466 // due to NWF this is variable
2467 long nCloserHeight = ((MenuBarWindow*) pWindow)->MinCloseButtonSize().Height();
2468 if( aSz.Height() < nCloserHeight )
2469 aSz.Height() = nCloserHeight;
2472 if ( pLogo )
2473 aSz.Width() += pLogo->aBitmap.GetSizePixel().Width();
2475 return aSz;
2478 static void ImplPaintCheckBackground( Window* i_pWindow, const Rectangle& i_rRect, bool i_bHighlight )
2480 BOOL bNativeOk = FALSE;
2481 if( i_pWindow->IsNativeControlSupported( CTRL_TOOLBAR, PART_BUTTON ) )
2483 ImplControlValue aControlValue;
2484 Region aCtrlRegion( i_rRect );
2485 ControlState nState = CTRL_STATE_PRESSED | CTRL_STATE_ENABLED;
2487 aControlValue.setTristateVal( BUTTONVALUE_ON );
2489 bNativeOk = i_pWindow->DrawNativeControl( CTRL_TOOLBAR, PART_BUTTON,
2490 aCtrlRegion, nState, aControlValue,
2491 rtl::OUString() );
2494 if( ! bNativeOk )
2496 const StyleSettings& rSettings = i_pWindow->GetSettings().GetStyleSettings();
2497 Color aColor( i_bHighlight ? rSettings.GetMenuHighlightTextColor() : rSettings.GetHighlightColor() );
2498 i_pWindow->DrawSelectionBackground( i_rRect, 0, i_bHighlight, TRUE, FALSE, 2, NULL, &aColor );
2502 void Menu::ImplPaint( Window* pWin, USHORT nBorder, long nStartY, MenuItemData* pThisItemOnly, BOOL bHighlighted, bool bLayout ) const
2504 // Fuer Symbole: nFontHeight x nFontHeight
2505 long nFontHeight = pWin->GetTextHeight();
2506 long nExtra = nFontHeight/4;
2508 long nCheckHeight = 0, nRadioHeight = 0, nMaxCheckWidth = 0;
2509 ImplGetNativeCheckAndRadioSize( pWin, nCheckHeight, nRadioHeight, nMaxCheckWidth );
2511 DecorationView aDecoView( pWin );
2512 const StyleSettings& rSettings = pWin->GetSettings().GetStyleSettings();
2514 Point aTopLeft, aTmpPos;
2516 if ( pLogo )
2517 aTopLeft.X() = pLogo->aBitmap.GetSizePixel().Width();
2519 int nOuterSpace = 0;
2520 if( !bIsMenuBar )
2522 nOuterSpace = ImplGetSVData()->maNWFData.mnMenuFormatExtraBorder;
2523 aTopLeft.X() += nOuterSpace;
2524 aTopLeft.Y() += nOuterSpace;
2527 Size aOutSz = pWin->GetOutputSizePixel();
2528 USHORT nCount = (USHORT)pItemList->Count();
2529 if( bLayout )
2530 mpLayoutData->m_aVisibleItemBoundRects.clear();
2531 for ( USHORT n = 0; n < nCount; n++ )
2533 MenuItemData* pData = pItemList->GetDataFromPos( n );
2534 if ( ImplIsVisible( n ) && ( !pThisItemOnly || ( pData == pThisItemOnly ) ) )
2536 if ( pThisItemOnly && bHighlighted )
2537 pWin->SetTextColor( rSettings.GetMenuHighlightTextColor() );
2539 Point aPos( aTopLeft );
2540 aPos.Y() += nBorder;
2541 aPos.Y() += nStartY;
2543 if ( aPos.Y() >= 0 )
2545 long nTextOffsetY = ((pData->aSz.Height()-nFontHeight)/2);
2546 if( bIsMenuBar )
2547 nTextOffsetY += (aOutSz.Height()-pData->aSz.Height()) / 2;
2548 USHORT nTextStyle = 0;
2549 USHORT nSymbolStyle = 0;
2550 USHORT nImageStyle = 0;
2551 // SubMenus ohne Items werden nicht mehr disablte dargestellt,
2552 // wenn keine Items enthalten sind, da die Anwendung selber
2553 // darauf achten muss. Ansonsten gibt es Faelle, wo beim
2554 // asyncronen laden die Eintraege disablte dargestellt werden.
2555 if ( !pData->bEnabled )
2557 nTextStyle |= TEXT_DRAW_DISABLE;
2558 nSymbolStyle |= SYMBOL_DRAW_DISABLE;
2559 nImageStyle |= IMAGE_DRAW_DISABLE;
2562 // Separator
2563 if ( !bLayout && !bIsMenuBar && ( pData->eType == MENUITEM_SEPARATOR ) )
2565 aTmpPos.Y() = aPos.Y() + ((pData->aSz.Height()-2)/2);
2566 aTmpPos.X() = aPos.X() + 2 + nOuterSpace;
2567 pWin->SetLineColor( rSettings.GetShadowColor() );
2568 pWin->DrawLine( aTmpPos, Point( aOutSz.Width() - 3 - 2*nOuterSpace, aTmpPos.Y() ) );
2569 aTmpPos.Y()++;
2570 pWin->SetLineColor( rSettings.GetLightColor() );
2571 pWin->DrawLine( aTmpPos, Point( aOutSz.Width() - 3 - 2*nOuterSpace, aTmpPos.Y() ) );
2572 pWin->SetLineColor();
2575 Rectangle aOuterCheckRect( Point( aPos.X()+nCheckPos, aPos.Y() ), Size( pData->aSz.Height(), pData->aSz.Height() ) );
2576 aOuterCheckRect.Left() += 1;
2577 aOuterCheckRect.Right() -= 1;
2578 aOuterCheckRect.Top() += 1;
2579 aOuterCheckRect.Bottom() -= 1;
2581 // CheckMark
2582 if ( !bLayout && !bIsMenuBar && pData->HasCheck() )
2584 // draw selection transparent marker if checked
2585 // onto that either a checkmark or the item image
2586 // will be painted
2587 // however do not do this if native checks will be painted since
2588 // the selection color too often does not fit the theme's check and/or radio
2590 if( ! ( ( pData->eType == MENUITEM_IMAGE ) || ( pData->eType == MENUITEM_STRINGIMAGE ) ) )
2592 if ( pWin->IsNativeControlSupported( CTRL_MENU_POPUP,
2593 (pData->nBits & MIB_RADIOCHECK)
2594 ? PART_MENU_ITEM_CHECK_MARK
2595 : PART_MENU_ITEM_RADIO_MARK ) )
2597 ControlPart nPart = ((pData->nBits & MIB_RADIOCHECK)
2598 ? PART_MENU_ITEM_RADIO_MARK
2599 : PART_MENU_ITEM_CHECK_MARK);
2601 ControlState nState = 0;
2603 if ( pData->bChecked )
2604 nState |= CTRL_STATE_PRESSED;
2606 if ( pData->bEnabled )
2607 nState |= CTRL_STATE_ENABLED;
2609 if ( bHighlighted )
2610 nState |= CTRL_STATE_SELECTED;
2612 long nCtrlHeight = (pData->nBits & MIB_RADIOCHECK) ? nCheckHeight : nRadioHeight;
2613 aTmpPos.X() = aOuterCheckRect.Left() + (aOuterCheckRect.GetWidth() - nCtrlHeight)/2;
2614 aTmpPos.Y() = aOuterCheckRect.Top() + (aOuterCheckRect.GetHeight() - nCtrlHeight)/2;
2616 Rectangle aCheckRect( aTmpPos, Size( nCtrlHeight, nCtrlHeight ) );
2617 pWin->DrawNativeControl( CTRL_MENU_POPUP, nPart,
2618 Region( aCheckRect ),
2619 nState,
2620 ImplControlValue(),
2621 OUString() );
2623 else if ( pData->bChecked ) // by default do nothing for unchecked items
2625 ImplPaintCheckBackground( pWin, aOuterCheckRect, pThisItemOnly && bHighlighted );
2627 SymbolType eSymbol;
2628 Size aSymbolSize;
2629 if ( pData->nBits & MIB_RADIOCHECK )
2631 eSymbol = SYMBOL_RADIOCHECKMARK;
2632 aSymbolSize = Size( nFontHeight/2, nFontHeight/2 );
2634 else
2636 eSymbol = SYMBOL_CHECKMARK;
2637 aSymbolSize = Size( (nFontHeight*25)/40, nFontHeight/2 );
2639 aTmpPos.X() = aOuterCheckRect.Left() + (aOuterCheckRect.GetWidth() - aSymbolSize.Width())/2;
2640 aTmpPos.Y() = aOuterCheckRect.Top() + (aOuterCheckRect.GetHeight() - aSymbolSize.Height())/2;
2641 Rectangle aRect( aTmpPos, aSymbolSize );
2642 aDecoView.DrawSymbol( aRect, eSymbol, pWin->GetTextColor(), nSymbolStyle );
2647 // Image:
2648 if ( !bLayout && !bIsMenuBar && ( ( pData->eType == MENUITEM_IMAGE ) || ( pData->eType == MENUITEM_STRINGIMAGE ) ) )
2650 // Don't render an image for a check thing
2651 if ((nMenuFlags & MENU_FLAG_SHOWCHECKIMAGES) || !pData->HasCheck() )
2653 if( pData->bChecked )
2654 ImplPaintCheckBackground( pWin, aOuterCheckRect, pThisItemOnly && bHighlighted );
2655 aTmpPos = aOuterCheckRect.TopLeft();
2656 aTmpPos.X() += (aOuterCheckRect.GetWidth()-pData->aImage.GetSizePixel().Width())/2;
2657 aTmpPos.Y() += (aOuterCheckRect.GetHeight()-pData->aImage.GetSizePixel().Height())/2;
2658 pWin->DrawImage( aTmpPos, pData->aImage, nImageStyle );
2662 // Text:
2663 if ( ( pData->eType == MENUITEM_STRING ) || ( pData->eType == MENUITEM_STRINGIMAGE ) )
2665 aTmpPos.X() = aPos.X() + nTextPos;
2666 aTmpPos.Y() = aPos.Y();
2667 aTmpPos.Y() += nTextOffsetY;
2668 USHORT nStyle = nTextStyle|TEXT_DRAW_MNEMONIC;
2669 if ( pData->bIsTemporary )
2670 nStyle |= TEXT_DRAW_DISABLE;
2671 MetricVector* pVector = bLayout ? &mpLayoutData->m_aUnicodeBoundRects : NULL;
2672 String* pDisplayText = bLayout ? &mpLayoutData->m_aDisplayText : NULL;
2673 if( bLayout )
2675 mpLayoutData->m_aLineIndices.push_back( mpLayoutData->m_aDisplayText.Len() );
2676 mpLayoutData->m_aLineItemIds.push_back( pData->nId );
2677 mpLayoutData->m_aLineItemPositions.push_back( n );
2679 // #i47946# with NWF painted menus the background is transparent
2680 // since DrawCtrlText can depend on the background (e.g. for
2681 // TEXT_DRAW_DISABLE), temporarily set a background which
2682 // hopefully matches the NWF background since it is read
2683 // from the system style settings
2684 bool bSetTmpBackground = !pWin->IsBackground() && pWin->IsNativeControlSupported( CTRL_MENU_POPUP, PART_ENTIRE_CONTROL );
2685 if( bSetTmpBackground )
2687 Color aBg = bIsMenuBar ?
2688 pWin->GetSettings().GetStyleSettings().GetMenuBarColor() :
2689 pWin->GetSettings().GetStyleSettings().GetMenuColor();
2690 pWin->SetBackground( Wallpaper( aBg ) );
2692 pWin->DrawCtrlText( aTmpPos, pData->aText, 0, pData->aText.Len(), nStyle, pVector, pDisplayText );
2693 if( bSetTmpBackground )
2694 pWin->SetBackground();
2697 // Accel
2698 if ( !bLayout && !bIsMenuBar && pData->aAccelKey.GetCode() && !ImplAccelDisabled() )
2700 XubString aAccText = pData->aAccelKey.GetName();
2701 aTmpPos.X() = aOutSz.Width() - pWin->GetTextWidth( aAccText );
2702 aTmpPos.X() -= 4*nExtra;
2704 aTmpPos.X() -= nOuterSpace;
2705 aTmpPos.Y() = aPos.Y();
2706 aTmpPos.Y() += nTextOffsetY;
2707 pWin->DrawCtrlText( aTmpPos, aAccText, 0, aAccText.Len(), nTextStyle );
2710 // SubMenu?
2711 if ( !bLayout && !bIsMenuBar && pData->pSubMenu )
2713 aTmpPos.X() = aOutSz.Width() - nFontHeight + nExtra - nOuterSpace;
2714 aTmpPos.Y() = aPos.Y();
2715 aTmpPos.Y() += nExtra/2;
2716 aTmpPos.Y() += ( pData->aSz.Height() / 2 ) - ( nFontHeight/4 );
2717 if ( pData->nBits & MIB_POPUPSELECT )
2719 pWin->SetTextColor( rSettings.GetMenuTextColor() );
2720 Point aTmpPos2( aPos );
2721 aTmpPos2.X() = aOutSz.Width() - nFontHeight - nFontHeight/4;
2722 aDecoView.DrawFrame(
2723 Rectangle( aTmpPos2, Size( nFontHeight+nFontHeight/4, pData->aSz.Height() ) ), FRAME_DRAW_GROUP );
2725 aDecoView.DrawSymbol(
2726 Rectangle( aTmpPos, Size( nFontHeight/2, nFontHeight/2 ) ),
2727 SYMBOL_SPIN_RIGHT, pWin->GetTextColor(), nSymbolStyle );
2728 // if ( pData->nBits & MIB_POPUPSELECT )
2729 // {
2730 // aTmpPos.Y() += nFontHeight/2 ;
2731 // pWin->SetLineColor( rSettings.GetShadowColor() );
2732 // pWin->DrawLine( aTmpPos, Point( aTmpPos.X() + nFontHeight/3, aTmpPos.Y() ) );
2733 // pWin->SetLineColor( rSettings.GetLightColor() );
2734 // aTmpPos.Y()++;
2735 // pWin->DrawLine( aTmpPos, Point( aTmpPos.X() + nFontHeight/3, aTmpPos.Y() ) );
2736 // pWin->SetLineColor();
2737 // }
2740 if ( pThisItemOnly && bHighlighted )
2742 // This restores the normal menu or menu bar text
2743 // color for when it is no longer highlighted.
2744 if ( bIsMenuBar )
2745 pWin->SetTextColor( rSettings.GetMenuBarTextColor() );
2746 else
2747 pWin->SetTextColor( rSettings.GetMenuTextColor() );
2750 if( bLayout )
2752 if ( !bIsMenuBar )
2753 mpLayoutData->m_aVisibleItemBoundRects[ n ] = Rectangle( aTopLeft, Size( aOutSz.Width(), pData->aSz.Height() ) );
2754 else
2755 mpLayoutData->m_aVisibleItemBoundRects[ n ] = Rectangle( aTopLeft, pData->aSz );
2759 if ( !bIsMenuBar )
2761 aTopLeft.Y() += pData->aSz.Height();
2763 else
2765 aTopLeft.X() += pData->aSz.Width();
2769 if ( !bLayout && !pThisItemOnly && pLogo )
2771 Size aLogoSz = pLogo->aBitmap.GetSizePixel();
2773 Rectangle aRect( Point( 0, 0 ), Point( aLogoSz.Width()-1, aOutSz.Height() ) );
2774 if ( pWin->GetColorCount() >= 256 )
2776 Gradient aGrad( GRADIENT_LINEAR, pLogo->aStartColor, pLogo->aEndColor );
2777 aGrad.SetAngle( 1800 );
2778 aGrad.SetBorder( 15 );
2779 pWin->DrawGradient( aRect, aGrad );
2781 else
2783 pWin->SetFillColor( pLogo->aStartColor );
2784 pWin->DrawRect( aRect );
2787 Point aLogoPos( 0, aOutSz.Height() - aLogoSz.Height() );
2788 pLogo->aBitmap.Draw( pWin, aLogoPos );
2792 Menu* Menu::ImplGetStartMenu()
2794 Menu* pStart = this;
2795 while ( pStart && pStart->pStartedFrom && ( pStart->pStartedFrom != pStart ) )
2796 pStart = pStart->pStartedFrom;
2797 return pStart;
2800 void Menu::ImplCallHighlight( USHORT nHighlightedItem )
2802 nSelectedId = 0;
2803 MenuItemData* pData = pItemList->GetDataFromPos( nHighlightedItem );
2804 if ( pData )
2805 nSelectedId = pData->nId;
2806 ImplCallEventListeners( VCLEVENT_MENU_HIGHLIGHT, GetItemPos( GetCurItemId() ) );
2807 Highlight();
2808 nSelectedId = 0;
2811 IMPL_LINK( Menu, ImplCallSelect, Menu*, EMPTYARG )
2813 nEventId = 0;
2814 Select();
2815 return 0;
2818 Menu* Menu::ImplFindSelectMenu()
2820 Menu* pSelMenu = nEventId ? this : NULL;
2822 for ( ULONG n = GetItemList()->Count(); n && !pSelMenu; )
2824 MenuItemData* pData = GetItemList()->GetDataFromPos( --n );
2826 if ( pData->pSubMenu )
2827 pSelMenu = pData->pSubMenu->ImplFindSelectMenu();
2830 return pSelMenu;
2833 Menu* Menu::ImplFindMenu( USHORT nItemId )
2835 Menu* pSelMenu = NULL;
2837 for ( ULONG n = GetItemList()->Count(); n && !pSelMenu; )
2839 MenuItemData* pData = GetItemList()->GetDataFromPos( --n );
2841 if( pData->nId == nItemId )
2842 pSelMenu = this;
2843 else if ( pData->pSubMenu )
2844 pSelMenu = pData->pSubMenu->ImplFindMenu( nItemId );
2847 return pSelMenu;
2850 void Menu::RemoveDisabledEntries( BOOL bCheckPopups, BOOL bRemoveEmptyPopups )
2852 for ( USHORT n = 0; n < GetItemCount(); n++ )
2854 BOOL bRemove = FALSE;
2855 MenuItemData* pItem = pItemList->GetDataFromPos( n );
2856 if ( pItem->eType == MENUITEM_SEPARATOR )
2858 if ( !n || ( GetItemType( n-1 ) == MENUITEM_SEPARATOR ) )
2859 bRemove = TRUE;
2861 else
2862 bRemove = !pItem->bEnabled;
2864 if ( bCheckPopups && pItem->pSubMenu )
2866 pItem->pSubMenu->RemoveDisabledEntries( TRUE );
2867 if ( bRemoveEmptyPopups && !pItem->pSubMenu->GetItemCount() )
2868 bRemove = TRUE;
2871 if ( bRemove )
2872 RemoveItem( n-- );
2875 if ( GetItemCount() )
2877 USHORT nLast = GetItemCount() - 1;
2878 MenuItemData* pItem = pItemList->GetDataFromPos( nLast );
2879 if ( pItem->eType == MENUITEM_SEPARATOR )
2880 RemoveItem( nLast );
2882 delete mpLayoutData, mpLayoutData = NULL;
2885 BOOL Menu::HasValidEntries( BOOL bCheckPopups )
2887 BOOL bValidEntries = FALSE;
2888 USHORT nCount = GetItemCount();
2889 for ( USHORT n = 0; !bValidEntries && ( n < nCount ); n++ )
2891 MenuItemData* pItem = pItemList->GetDataFromPos( n );
2892 if ( pItem->bEnabled && ( pItem->eType != MENUITEM_SEPARATOR ) )
2894 if ( bCheckPopups && pItem->pSubMenu )
2895 bValidEntries = pItem->pSubMenu->HasValidEntries( TRUE );
2896 else
2897 bValidEntries = TRUE;
2900 return bValidEntries;
2903 void Menu::SetLogo( const MenuLogo& rLogo )
2905 delete pLogo;
2906 pLogo = new MenuLogo( rLogo );
2909 void Menu::SetLogo()
2911 delete pLogo;
2912 pLogo = NULL;
2915 MenuLogo Menu::GetLogo() const
2917 MenuLogo aLogo;
2918 if ( pLogo )
2919 aLogo = *pLogo;
2920 return aLogo;
2923 void Menu::ImplKillLayoutData() const
2925 delete mpLayoutData, mpLayoutData = NULL;
2928 void Menu::ImplFillLayoutData() const
2930 if( pWindow && pWindow->IsReallyVisible() )
2932 mpLayoutData = new MenuLayoutData();
2933 if( bIsMenuBar )
2935 ImplPaint( pWindow, 0, 0, 0, FALSE, true );
2937 else
2939 MenuFloatingWindow* pFloat = (MenuFloatingWindow*)pWindow;
2940 ImplPaint( pWindow, pFloat->nScrollerHeight, pFloat->ImplGetStartY(), 0, FALSE, true );
2945 String Menu::GetDisplayText() const
2947 if( ! mpLayoutData )
2948 ImplFillLayoutData();
2949 return mpLayoutData ? mpLayoutData->m_aDisplayText : String();
2952 Rectangle Menu::GetCharacterBounds( USHORT nItemID, long nIndex ) const
2954 long nItemIndex = -1;
2955 if( ! mpLayoutData )
2956 ImplFillLayoutData();
2957 if( mpLayoutData )
2959 for( size_t i = 0; i < mpLayoutData->m_aLineItemIds.size(); i++ )
2961 if( mpLayoutData->m_aLineItemIds[i] == nItemID )
2963 nItemIndex = mpLayoutData->m_aLineIndices[i];
2964 break;
2968 return (mpLayoutData && nItemIndex != -1) ? mpLayoutData->GetCharacterBounds( nItemIndex+nIndex ) : Rectangle();
2972 long Menu::GetIndexForPoint( const Point& rPoint, USHORT& rItemID ) const
2974 long nIndex = -1;
2975 rItemID = 0;
2976 if( ! mpLayoutData )
2977 ImplFillLayoutData();
2978 if( mpLayoutData )
2980 nIndex = mpLayoutData->GetIndexForPoint( rPoint );
2981 for( size_t i = 0; i < mpLayoutData->m_aLineIndices.size(); i++ )
2983 if( mpLayoutData->m_aLineIndices[i] <= nIndex &&
2984 (i == mpLayoutData->m_aLineIndices.size()-1 || mpLayoutData->m_aLineIndices[i+1] > nIndex) )
2986 // make index relative to item
2987 nIndex -= mpLayoutData->m_aLineIndices[i];
2988 rItemID = mpLayoutData->m_aLineItemIds[i];
2989 break;
2993 return nIndex;
2996 long Menu::GetLineCount() const
2998 if( ! mpLayoutData )
2999 ImplFillLayoutData();
3000 return mpLayoutData ? mpLayoutData->GetLineCount() : 0;
3003 Pair Menu::GetLineStartEnd( long nLine ) const
3005 if( ! mpLayoutData )
3006 ImplFillLayoutData();
3007 return mpLayoutData ? mpLayoutData->GetLineStartEnd( nLine ) : Pair( -1, -1 );
3010 Pair Menu::GetItemStartEnd( USHORT nItem ) const
3012 if( ! mpLayoutData )
3013 ImplFillLayoutData();
3015 for( size_t i = 0; i < mpLayoutData->m_aLineItemIds.size(); i++ )
3016 if( mpLayoutData->m_aLineItemIds[i] == nItem )
3017 return GetLineStartEnd( i );
3019 return Pair( -1, -1 );
3022 USHORT Menu::GetDisplayItemId( long nLine ) const
3024 USHORT nItemId = 0;
3025 if( ! mpLayoutData )
3026 ImplFillLayoutData();
3027 if( mpLayoutData && ( nLine >= 0 ) && ( nLine < (long)mpLayoutData->m_aLineItemIds.size() ) )
3028 nItemId = mpLayoutData->m_aLineItemIds[nLine];
3029 return nItemId;
3032 BOOL Menu::ConvertPoint( Point& rPoint, Window* pReferenceWindow ) const
3034 BOOL bRet = FALSE;
3035 if( pWindow && pReferenceWindow )
3037 rPoint = pReferenceWindow->OutputToAbsoluteScreenPixel( rPoint );
3038 rPoint = pWindow->AbsoluteScreenToOutputPixel( rPoint );
3039 bRet = TRUE;
3041 return bRet;
3044 Rectangle Menu::GetBoundingRectangle( USHORT nPos ) const
3046 Rectangle aRet;
3048 if( ! mpLayoutData )
3049 ImplFillLayoutData();
3050 if( mpLayoutData )
3052 std::map< USHORT, Rectangle >::const_iterator it = mpLayoutData->m_aVisibleItemBoundRects.find( nPos );
3053 if( it != mpLayoutData->m_aVisibleItemBoundRects.end() )
3054 aRet = it->second;
3056 return aRet;
3059 void Menu::SetAccessibleName( USHORT nItemId, const XubString& rStr )
3061 USHORT nPos;
3062 MenuItemData* pData = pItemList->GetData( nItemId, nPos );
3064 if ( pData && !rStr.Equals( pData->aAccessibleName ) )
3066 pData->aAccessibleName = rStr;
3067 ImplCallEventListeners( VCLEVENT_MENU_ACCESSIBLENAMECHANGED, nPos );
3071 XubString Menu::GetAccessibleName( USHORT nItemId ) const
3073 MenuItemData* pData = pItemList->GetData( nItemId );
3075 if ( pData )
3076 return pData->aAccessibleName;
3077 else
3078 return ImplGetSVEmptyStr();
3081 void Menu::SetAccessibleDescription( USHORT nItemId, const XubString& rStr )
3083 MenuItemData* pData = pItemList->GetData( nItemId );
3085 if ( pData )
3086 pData->aAccessibleDescription = rStr;
3089 XubString Menu::GetAccessibleDescription( USHORT nItemId ) const
3091 MenuItemData* pData = pItemList->GetData( nItemId );
3093 if ( pData )
3094 return pData->aAccessibleDescription;
3095 else
3096 return ImplGetSVEmptyStr();
3099 void Menu::ImplSetSalMenu( SalMenu *pSalMenu )
3101 if( mpSalMenu )
3102 ImplGetSVData()->mpDefInst->DestroyMenu( mpSalMenu );
3103 mpSalMenu = pSalMenu;
3106 BOOL Menu::GetSystemMenuData( SystemMenuData* pData ) const
3108 Menu* pMenu = (Menu*)this;
3109 if( pData && pMenu->ImplGetSalMenu() )
3111 pMenu->ImplGetSalMenu()->GetSystemMenuData( pData );
3112 return TRUE;
3114 else
3115 return FALSE;
3118 bool Menu::IsHighlighted( USHORT nItemPos ) const
3120 bool bRet = false;
3122 if( pWindow )
3124 if( bIsMenuBar )
3125 bRet = ( nItemPos == static_cast< MenuBarWindow * > (pWindow)->GetHighlightedItem() );
3126 else
3127 bRet = ( nItemPos == static_cast< MenuFloatingWindow * > (pWindow)->GetHighlightedItem() );
3130 return bRet;
3133 void Menu::HighlightItem( USHORT nItemPos )
3135 if ( pWindow )
3137 if ( bIsMenuBar )
3139 MenuBarWindow* pMenuWin = static_cast< MenuBarWindow* >( pWindow );
3140 pMenuWin->SetAutoPopup( FALSE );
3141 pMenuWin->ChangeHighlightItem( nItemPos, FALSE );
3143 else
3145 static_cast< MenuFloatingWindow* >( pWindow )->ChangeHighlightItem( nItemPos, FALSE );
3150 // -----------
3151 // - MenuBar -
3152 // -----------
3154 MenuBar::MenuBar() : Menu( TRUE )
3156 mbDisplayable = TRUE;
3157 mbCloserVisible = FALSE;
3158 mbFloatBtnVisible = FALSE;
3159 mbHideBtnVisible = FALSE;
3162 MenuBar::MenuBar( const MenuBar& rMenu ) : Menu( TRUE )
3164 mbDisplayable = TRUE;
3165 mbCloserVisible = FALSE;
3166 mbFloatBtnVisible = FALSE;
3167 mbHideBtnVisible = FALSE;
3168 *this = rMenu;
3169 bIsMenuBar = TRUE;
3172 MenuBar::MenuBar( const ResId& rResId ) : Menu ( TRUE )
3174 mbDisplayable = TRUE;
3175 mbCloserVisible = FALSE;
3176 mbFloatBtnVisible = FALSE;
3177 mbHideBtnVisible = FALSE;
3178 ImplLoadRes( rResId );
3181 MenuBar::~MenuBar()
3183 ImplDestroy( this, TRUE );
3186 void MenuBar::ShowCloser( BOOL bShow )
3188 ShowButtons( bShow, mbFloatBtnVisible, mbHideBtnVisible );
3191 void MenuBar::ShowFloatButton( BOOL bShow )
3193 ShowButtons( mbCloserVisible, bShow, mbHideBtnVisible );
3196 void MenuBar::ShowHideButton( BOOL bShow )
3198 ShowButtons( mbCloserVisible, mbFloatBtnVisible, bShow );
3201 void MenuBar::ShowButtons( BOOL bClose, BOOL bFloat, BOOL bHide )
3203 if ( (bClose != mbCloserVisible) ||
3204 (bFloat != mbFloatBtnVisible) ||
3205 (bHide != mbHideBtnVisible) )
3207 mbCloserVisible = bClose;
3208 mbFloatBtnVisible = bFloat;
3209 mbHideBtnVisible = bHide;
3210 if ( ImplGetWindow() )
3211 ((MenuBarWindow*)ImplGetWindow())->ShowButtons( bClose, bFloat, bHide );
3215 void MenuBar::SetDisplayable( BOOL bDisplayable )
3217 if( bDisplayable != mbDisplayable )
3219 mbDisplayable = bDisplayable;
3220 MenuBarWindow* pMenuWin = (MenuBarWindow*) ImplGetWindow();
3221 if( pMenuWin )
3222 pMenuWin->ImplLayoutChanged();
3226 Window* MenuBar::ImplCreate( Window* pParent, Window* pWindow, MenuBar* pMenu )
3228 if ( !pWindow )
3229 pWindow = new MenuBarWindow( pParent );
3231 pMenu->pStartedFrom = 0;
3232 pMenu->pWindow = pWindow;
3233 ((MenuBarWindow*)pWindow)->SetMenu( pMenu );
3234 long nHeight = pMenu->ImplCalcSize( pWindow ).Height();
3236 // depending on the native implementation or the displayable flag
3237 // the menubar windows is supressed (ie, height=0)
3238 if( !((MenuBar*) pMenu)->IsDisplayable() ||
3239 ( pMenu->ImplGetSalMenu() && pMenu->ImplGetSalMenu()->VisibleMenuBar() ) )
3240 nHeight = 0;
3242 pWindow->SetPosSizePixel( 0, 0, 0, nHeight, WINDOW_POSSIZE_HEIGHT );
3243 return pWindow;
3246 void MenuBar::ImplDestroy( MenuBar* pMenu, BOOL bDelete )
3248 MenuBarWindow* pWindow = (MenuBarWindow*) pMenu->ImplGetWindow();
3249 if ( pWindow && bDelete )
3251 pWindow->KillActivePopup();
3252 delete pWindow;
3254 pMenu->pWindow = NULL;
3257 BOOL MenuBar::ImplHandleKeyEvent( const KeyEvent& rKEvent, BOOL bFromMenu )
3259 BOOL bDone = FALSE;
3261 // No keyboard processing when system handles the menu or our menubar is invisible
3262 if( !IsDisplayable() ||
3263 ( ImplGetSalMenu() && ImplGetSalMenu()->VisibleMenuBar() ) )
3264 return bDone;
3266 // Enabled-Abfragen, falls diese Methode von einem anderen Fenster gerufen wurde...
3267 Window* pWin = ImplGetWindow();
3268 if ( pWin && pWin->IsEnabled() && pWin->IsInputEnabled() && ! pWin->IsInModalMode() )
3269 bDone = ((MenuBarWindow*)pWin)->ImplHandleKeyEvent( rKEvent, bFromMenu );
3270 return bDone;
3273 // -----------------------------------------------------------------------
3275 void MenuBar::SelectEntry( USHORT nId )
3277 MenuBarWindow* pMenuWin = (MenuBarWindow*) ImplGetWindow();
3279 if( pMenuWin )
3281 pMenuWin->GrabFocus();
3282 nId = GetItemPos( nId );
3284 // #99705# popup the selected menu
3285 pMenuWin->SetAutoPopup( TRUE );
3286 if( ITEMPOS_INVALID != pMenuWin->nHighlightedItem )
3288 pMenuWin->KillActivePopup();
3289 pMenuWin->ChangeHighlightItem( ITEMPOS_INVALID, FALSE );
3291 if( nId != ITEMPOS_INVALID )
3292 pMenuWin->ChangeHighlightItem( nId, FALSE );
3296 // -----------------------------------------------------------------------
3298 // handler for native menu selection and command events
3300 BOOL MenuBar::HandleMenuActivateEvent( Menu *pMenu ) const
3302 if( pMenu )
3304 pMenu->pStartedFrom = (Menu*)this;
3305 pMenu->bInCallback = TRUE;
3306 pMenu->Activate();
3307 pMenu->bInCallback = FALSE;
3309 return TRUE;
3312 BOOL MenuBar::HandleMenuDeActivateEvent( Menu *pMenu ) const
3314 if( pMenu )
3316 pMenu->pStartedFrom = (Menu*)this;
3317 pMenu->bInCallback = TRUE;
3318 pMenu->Deactivate();
3319 pMenu->bInCallback = FALSE;
3321 return TRUE;
3324 BOOL MenuBar::HandleMenuHighlightEvent( Menu *pMenu, USHORT nHighlightEventId ) const
3326 if( !pMenu )
3327 pMenu = ((Menu*) this)->ImplFindMenu( nHighlightEventId );
3328 if( pMenu )
3330 if( mnHighlightedItemPos != ITEMPOS_INVALID )
3331 pMenu->ImplCallEventListeners( VCLEVENT_MENU_DEHIGHLIGHT, mnHighlightedItemPos );
3333 pMenu->mnHighlightedItemPos = pMenu->GetItemPos( nHighlightEventId );
3334 pMenu->nSelectedId = nHighlightEventId;
3335 pMenu->pStartedFrom = (Menu*)this;
3336 pMenu->ImplCallHighlight( pMenu->mnHighlightedItemPos );
3337 return TRUE;
3339 else
3340 return FALSE;
3343 BOOL MenuBar::HandleMenuCommandEvent( Menu *pMenu, USHORT nCommandEventId ) const
3345 if( !pMenu )
3346 pMenu = ((Menu*) this)->ImplFindMenu( nCommandEventId );
3347 if( pMenu )
3349 pMenu->nSelectedId = nCommandEventId;
3350 pMenu->pStartedFrom = (Menu*)this;
3351 pMenu->ImplSelect();
3352 return TRUE;
3354 else
3355 return FALSE;
3358 USHORT MenuBar::AddMenuBarButton( const Image& i_rImage, const Link& i_rLink, USHORT i_nPos )
3360 return AddMenuBarButton( i_rImage, i_rLink, String(), i_nPos );
3363 USHORT MenuBar::AddMenuBarButton( const Image& i_rImage, const Link& i_rLink, const String& i_rToolTip, USHORT i_nPos )
3365 return pWindow ? static_cast<MenuBarWindow*>(pWindow)->AddMenuBarButton( i_rImage, i_rLink, i_rToolTip, i_nPos ) : 0;
3368 void MenuBar::SetMenuBarButtonHighlightHdl( USHORT nId, const Link& rLink )
3370 if( pWindow )
3371 static_cast<MenuBarWindow*>(pWindow)->SetMenuBarButtonHighlightHdl( nId, rLink );
3374 Rectangle MenuBar::GetMenuBarButtonRectPixel( USHORT nId )
3376 return pWindow ? static_cast<MenuBarWindow*>(pWindow)->GetMenuBarButtonRectPixel( nId ) : Rectangle();
3379 void MenuBar::RemoveMenuBarButton( USHORT nId )
3381 if( pWindow )
3382 static_cast<MenuBarWindow*>(pWindow)->RemoveMenuBarButton( nId );
3385 BOOL MenuBar::HandleMenuButtonEvent( Menu *, USHORT i_nButtonId ) const
3387 return static_cast<MenuBarWindow*>(pWindow)->HandleMenuButtonEvent( i_nButtonId );
3390 // -----------------------------------------------------------------------
3392 // BOOL PopupMenu::bAnyPopupInExecute = FALSE;
3394 PopupMenu::PopupMenu()
3396 pRefAutoSubMenu = NULL;
3399 PopupMenu::PopupMenu( const ResId& rResId )
3401 pRefAutoSubMenu = NULL;
3402 ImplLoadRes( rResId );
3405 PopupMenu::PopupMenu( const PopupMenu& rMenu ) : Menu()
3407 pRefAutoSubMenu = NULL;
3408 *this = rMenu;
3411 PopupMenu::~PopupMenu()
3413 if( pRefAutoSubMenu && *pRefAutoSubMenu == this )
3414 *pRefAutoSubMenu = NULL; // #111060# avoid second delete in ~MenuItemData
3417 BOOL PopupMenu::IsInExecute()
3419 return GetActivePopupMenu() ? TRUE : FALSE;
3422 PopupMenu* PopupMenu::GetActivePopupMenu()
3424 ImplSVData* pSVData = ImplGetSVData();
3425 return pSVData->maAppData.mpActivePopupMenu;
3428 void PopupMenu::EndExecute( USHORT nSelectId )
3430 if ( ImplGetWindow() )
3431 ImplGetFloatingWindow()->EndExecute( nSelectId );
3434 void PopupMenu::SelectEntry( USHORT nId )
3436 if ( ImplGetWindow() )
3438 if( nId != ITEMPOS_INVALID )
3440 USHORT nPos;
3441 MenuItemData* pData = GetItemList()->GetData( nId, nPos );
3442 if ( pData->pSubMenu )
3443 ImplGetFloatingWindow()->ChangeHighlightItem( nPos, TRUE );
3444 else
3445 ImplGetFloatingWindow()->EndExecute( nId );
3447 else
3449 MenuFloatingWindow* pFloat = ImplGetFloatingWindow();
3450 pFloat->GrabFocus();
3451 USHORT nPos;
3452 for( nPos = 0; nPos < GetItemList()->Count(); nPos++ )
3454 MenuItemData* pData = (MenuItemData*)GetItemList()->GetObject( nPos );
3455 if( pData->pSubMenu )
3457 pFloat->KillActivePopup();
3460 pFloat->ChangeHighlightItem( ITEMPOS_INVALID, FALSE );
3465 void PopupMenu::SetSelectedEntry( USHORT nId )
3467 nSelectedId = nId;
3470 USHORT PopupMenu::Execute( Window* pExecWindow, const Point& rPopupPos )
3472 return Execute( pExecWindow, Rectangle( rPopupPos, rPopupPos ), POPUPMENU_EXECUTE_DOWN );
3475 USHORT PopupMenu::Execute( Window* pExecWindow, const Rectangle& rRect, USHORT nFlags )
3477 ULONG nPopupModeFlags = 0;
3478 if ( nFlags & POPUPMENU_EXECUTE_DOWN )
3479 nPopupModeFlags = FLOATWIN_POPUPMODE_DOWN;
3480 else if ( nFlags & POPUPMENU_EXECUTE_UP )
3481 nPopupModeFlags = FLOATWIN_POPUPMODE_UP;
3482 else if ( nFlags & POPUPMENU_EXECUTE_LEFT )
3483 nPopupModeFlags = FLOATWIN_POPUPMODE_LEFT;
3484 else if ( nFlags & POPUPMENU_EXECUTE_RIGHT )
3485 nPopupModeFlags = FLOATWIN_POPUPMODE_RIGHT;
3486 else
3487 nPopupModeFlags = FLOATWIN_POPUPMODE_DOWN;
3489 if (nFlags & POPUPMENU_NOMOUSEUPCLOSE ) // allow popup menus to stay open on mouse button up
3490 nPopupModeFlags |= FLOATWIN_POPUPMODE_NOMOUSEUPCLOSE; // useful if the menu was opened on mousebutton down (eg toolbox configuration)
3492 return ImplExecute( pExecWindow, rRect, nPopupModeFlags, 0, FALSE );
3495 USHORT PopupMenu::ImplExecute( Window* pW, const Rectangle& rRect, ULONG nPopupModeFlags, Menu* pSFrom, BOOL bPreSelectFirst )
3497 if ( !pSFrom && ( PopupMenu::IsInExecute() || !GetItemCount() ) )
3498 return 0;
3500 delete mpLayoutData, mpLayoutData = NULL;
3502 ImplSVData* pSVData = ImplGetSVData();
3504 pStartedFrom = pSFrom;
3505 nSelectedId = 0;
3506 bCanceled = FALSE;
3508 ULONG nFocusId = 0;
3509 BOOL bRealExecute = FALSE;
3510 if ( !pStartedFrom )
3512 pSVData->maWinData.mbNoDeactivate = TRUE;
3513 nFocusId = Window::SaveFocus();
3514 bRealExecute = TRUE;
3516 else
3518 // assure that only one menu is open at a time
3519 if( pStartedFrom->bIsMenuBar && pSVData->maWinData.mpFirstFloat )
3520 pSVData->maWinData.mpFirstFloat->EndPopupMode( FLOATWIN_POPUPMODEEND_CANCEL | FLOATWIN_POPUPMODEEND_CLOSEALL );
3523 DBG_ASSERT( !ImplGetWindow(), "Win?!" );
3524 Rectangle aRect( rRect );
3525 aRect.SetPos( pW->OutputToScreenPixel( aRect.TopLeft() ) );
3527 WinBits nStyle = WB_BORDER;
3528 if ( bRealExecute )
3529 nPopupModeFlags |= FLOATWIN_POPUPMODE_NEWLEVEL;
3530 if ( !pStartedFrom || !pStartedFrom->bIsMenuBar )
3531 nPopupModeFlags |= FLOATWIN_POPUPMODE_PATHMOUSECANCELCLICK | FLOATWIN_POPUPMODE_ALLMOUSEBUTTONCLOSE;
3533 nPopupModeFlags |= FLOATWIN_POPUPMODE_NOKEYCLOSE;
3535 // Kann beim Debuggen hilfreich sein.
3536 // nPopupModeFlags |= FLOATWIN_POPUPMODE_NOFOCUSCLOSE;
3538 ImplDelData aDelData;
3539 pW->ImplAddDel( &aDelData );
3541 bInCallback = TRUE; // hier schon setzen, falls Activate ueberladen
3542 Activate();
3543 bInCallback = FALSE;
3545 if ( aDelData.IsDelete() )
3546 return 0; // Error
3548 pW->ImplRemoveDel( &aDelData );
3550 if ( bCanceled || bKilled )
3551 return 0;
3553 if ( !GetItemCount() )
3554 return 0;
3556 // Das Flag MENU_FLAG_HIDEDISABLEDENTRIES wird vererbt.
3557 if ( pSFrom )
3559 if ( pSFrom->nMenuFlags & MENU_FLAG_HIDEDISABLEDENTRIES )
3560 nMenuFlags |= MENU_FLAG_HIDEDISABLEDENTRIES;
3561 else
3562 nMenuFlags &= ~MENU_FLAG_HIDEDISABLEDENTRIES;
3564 else
3565 // #102790# context menues shall never show disabled entries
3566 nMenuFlags |= MENU_FLAG_HIDEDISABLEDENTRIES;
3569 USHORT nVisibleEntries = ImplGetVisibleItemCount();
3570 if ( !nVisibleEntries )
3572 ResMgr* pResMgr = ImplGetResMgr();
3573 if( pResMgr )
3575 String aTmpEntryText( ResId( SV_RESID_STRING_NOSELECTIONPOSSIBLE, *pResMgr ) );
3576 MenuItemData* pData = pItemList->Insert(
3577 0xFFFF, MENUITEM_STRING, 0, aTmpEntryText, Image(), NULL, 0xFFFF );
3578 pData->bIsTemporary = TRUE;
3581 else if ( Application::GetSettings().GetStyleSettings().GetAutoMnemonic() && !( nMenuFlags & MENU_FLAG_NOAUTOMNEMONICS ) )
3583 CreateAutoMnemonics();
3586 MenuFloatingWindow* pWin = new MenuFloatingWindow( this, pW, nStyle | WB_SYSTEMWINDOW );
3587 if( pSVData->maNWFData.mbFlatMenu )
3588 pWin->SetBorderStyle( WINDOW_BORDER_NOBORDER );
3589 else
3590 pWin->SetBorderStyle( pWin->GetBorderStyle() | WINDOW_BORDER_MENU );
3591 pWindow = pWin;
3593 Size aSz = ImplCalcSize( pWin );
3595 long nMaxHeight = pWin->GetDesktopRectPixel().GetHeight();
3596 if( Application::GetScreenCount() > 1 && ! Application::IsMultiDisplay() )
3598 Window* pDeskW = pWindow->GetWindow( WINDOW_REALPARENT );
3599 if( ! pDeskW )
3600 pDeskW = pWindow;
3601 Point aDesktopTL( pDeskW->OutputToAbsoluteScreenPixel( aRect.TopLeft() ) );
3602 nMaxHeight = Application::GetWorkAreaPosSizePixel(
3603 Application::GetBestScreen( Rectangle( aDesktopTL, aRect.GetSize() ) )
3604 ).GetHeight();
3606 if ( pStartedFrom && pStartedFrom->bIsMenuBar )
3607 nMaxHeight -= pW->GetSizePixel().Height();
3608 sal_Int32 nLeft, nTop, nRight, nBottom;
3609 pWindow->GetBorder( nLeft, nTop, nRight, nBottom );
3610 nMaxHeight -= nTop+nBottom;
3611 if ( aSz.Height() > nMaxHeight )
3613 pWin->EnableScrollMenu( TRUE );
3614 USHORT nStart = ImplGetFirstVisible();
3615 USHORT nEntries = ImplCalcVisEntries( nMaxHeight, nStart );
3616 aSz.Height() = ImplCalcHeight( nEntries );
3619 pWin->SetFocusId( nFocusId );
3620 pWin->SetOutputSizePixel( aSz );
3621 // #102158# menus must never grab the focus, otherwise
3622 // they will be closed immediately
3623 // from now on focus grabbing is only prohibited automatically if
3624 // FLOATWIN_POPUPMODE_GRABFOCUS was set (which is done below), because some
3625 // floaters (like floating toolboxes) may grab the focus
3626 // pWin->GrabFocus();
3627 if ( GetItemCount() )
3629 SalMenu* pMenu = ImplGetSalMenu();
3630 if( pMenu && pMenu->ShowNativePopupMenu( pWin, aRect, nPopupModeFlags | FLOATWIN_POPUPMODE_GRABFOCUS ) )
3632 pWin->StopExecute(0);
3633 pWin->doShutdown();
3634 pWindow->doLazyDelete();
3635 pWindow = NULL;
3636 return nSelectedId;
3638 else
3640 pWin->StartPopupMode( aRect, nPopupModeFlags | FLOATWIN_POPUPMODE_GRABFOCUS );
3642 if( pSFrom )
3644 USHORT aPos;
3645 if( pSFrom->bIsMenuBar )
3646 aPos = ((MenuBarWindow *) pSFrom->pWindow)->GetHighlightedItem();
3647 else
3648 aPos = ((MenuFloatingWindow *) pSFrom->pWindow)->GetHighlightedItem();
3650 pWin->SetPosInParent( aPos ); // store position to be sent in SUBMENUDEACTIVATE
3651 pSFrom->ImplCallEventListeners( VCLEVENT_MENU_SUBMENUACTIVATE, aPos );
3654 if ( bPreSelectFirst )
3656 USHORT nCount = (USHORT)pItemList->Count();
3657 for ( USHORT n = 0; n < nCount; n++ )
3659 MenuItemData* pData = pItemList->GetDataFromPos( n );
3660 if ( ( pData->bEnabled || !Application::GetSettings().GetStyleSettings().GetSkipDisabledInMenus() )
3661 && ( pData->eType != MENUITEM_SEPARATOR ) && ImplIsVisible( n ) && ImplIsSelectable( n ) )
3663 pWin->ChangeHighlightItem( n, FALSE );
3664 break;
3668 if ( bRealExecute )
3670 pWin->ImplAddDel( &aDelData );
3672 ImplDelData aModalWinDel;
3673 pW->ImplAddDel( &aModalWinDel );
3674 pW->ImplIncModalCount();
3676 pWin->Execute();
3678 DBG_ASSERT( ! aModalWinDel.IsDead(), "window for popup died, modal count incorrect !" );
3679 if( ! aModalWinDel.IsDead() )
3680 pW->ImplDecModalCount();
3682 if ( !aDelData.IsDelete() )
3683 pWin->ImplRemoveDel( &aDelData );
3684 else
3685 return 0;
3687 // Focus wieder herstellen (kann schon im Select wieder
3688 // hergestellt wurden sein
3689 nFocusId = pWin->GetFocusId();
3690 if ( nFocusId )
3692 pWin->SetFocusId( 0 );
3693 pSVData->maWinData.mbNoDeactivate = FALSE;
3695 pWin->ImplEndPopupMode( 0, nFocusId );
3697 if ( nSelectedId ) // Dann abraeumen... ( sonst macht TH das )
3699 PopupMenu* pSub = pWin->GetActivePopup();
3700 while ( pSub )
3702 pSub->ImplGetFloatingWindow()->EndPopupMode();
3703 pSub = pSub->ImplGetFloatingWindow()->GetActivePopup();
3706 pWin->doShutdown();
3707 pWindow->doLazyDelete();
3708 pWindow = NULL;
3710 // Steht noch ein Select aus?
3711 Menu* pSelect = ImplFindSelectMenu();
3712 if ( pSelect )
3714 // Beim Popup-Menu muss das Select vor dem Verlassen von Execute gerufen werden!
3715 Application::RemoveUserEvent( pSelect->nEventId );
3716 pSelect->nEventId = 0;
3717 pSelect->Select();
3721 return bRealExecute ? nSelectedId : 0;
3724 USHORT PopupMenu::ImplCalcVisEntries( long nMaxHeight, USHORT nStartEntry, USHORT* pLastVisible ) const
3726 nMaxHeight -= 2 * ImplGetFloatingWindow()->GetScrollerHeight();
3728 long nHeight = 0;
3729 USHORT nEntries = (USHORT) pItemList->Count();
3730 USHORT nVisEntries = 0;
3732 if ( pLastVisible )
3733 *pLastVisible = 0;
3735 for ( USHORT n = nStartEntry; n < nEntries; n++ )
3737 if ( ImplIsVisible( n ) )
3739 MenuItemData* pData = pItemList->GetDataFromPos( n );
3740 nHeight += pData->aSz.Height();
3741 if ( nHeight > nMaxHeight )
3742 break;
3744 if ( pLastVisible )
3745 *pLastVisible = n;
3746 nVisEntries++;
3749 return nVisEntries;
3752 long PopupMenu::ImplCalcHeight( USHORT nEntries ) const
3754 long nHeight = 0;
3756 USHORT nFound = 0;
3757 for ( USHORT n = 0; ( nFound < nEntries ) && ( n < pItemList->Count() ); n++ )
3759 if ( ImplIsVisible( (USHORT) n ) )
3761 MenuItemData* pData = pItemList->GetDataFromPos( n );
3762 nHeight += pData->aSz.Height();
3763 nFound++;
3767 nHeight += 2*ImplGetFloatingWindow()->GetScrollerHeight();
3769 return nHeight;
3773 static void ImplInitMenuWindow( Window* pWin, BOOL bFont, BOOL bMenuBar )
3775 const StyleSettings& rStyleSettings = pWin->GetSettings().GetStyleSettings();
3777 if ( bFont )
3778 pWin->SetPointFont( rStyleSettings.GetMenuFont() );
3779 if( bMenuBar )
3781 if( pWin->IsNativeControlSupported( CTRL_MENUBAR, PART_ENTIRE_CONTROL ) )
3783 pWin->SetBackground(); // background will be drawn by NWF
3785 else
3787 Wallpaper aWallpaper;
3788 aWallpaper.SetStyle( WALLPAPER_APPLICATIONGRADIENT );
3789 pWin->SetBackground( aWallpaper );
3790 pWin->SetPaintTransparent( FALSE );
3791 pWin->SetParentClipMode( 0 );
3794 else
3796 if( pWin->IsNativeControlSupported( CTRL_MENU_POPUP, PART_ENTIRE_CONTROL ) )
3798 pWin->SetBackground(); // background will be drawn by NWF
3800 else
3801 pWin->SetBackground( Wallpaper( rStyleSettings.GetMenuColor() ) );
3804 if ( bMenuBar )
3805 pWin->SetTextColor( rStyleSettings.GetMenuBarTextColor() );
3806 else
3807 pWin->SetTextColor( rStyleSettings.GetMenuTextColor() );
3808 pWin->SetTextFillColor();
3809 pWin->SetLineColor();
3812 MenuFloatingWindow::MenuFloatingWindow( Menu* pMen, Window* pParent, WinBits nStyle ) :
3813 FloatingWindow( pParent, nStyle )
3815 mpWindowImpl->mbMenuFloatingWindow= TRUE;
3816 pMenu = pMen;
3817 pActivePopup = 0;
3818 nSaveFocusId = 0;
3819 bInExecute = FALSE;
3820 bScrollMenu = FALSE;
3821 nHighlightedItem = ITEMPOS_INVALID;
3822 nMBDownPos = ITEMPOS_INVALID;
3823 nPosInParent = ITEMPOS_INVALID;
3824 nScrollerHeight = 0;
3825 // nStartY = 0;
3826 nBorder = EXTRASPACEY;
3827 nFirstEntry = 0;
3828 bScrollUp = FALSE;
3829 bScrollDown = FALSE;
3830 bIgnoreFirstMove = TRUE;
3831 bKeyInput = FALSE;
3833 EnableSaveBackground();
3834 ImplInitMenuWindow( this, TRUE, FALSE );
3836 SetPopupModeEndHdl( LINK( this, MenuFloatingWindow, PopupEnd ) );
3838 aHighlightChangedTimer.SetTimeoutHdl( LINK( this, MenuFloatingWindow, HighlightChanged ) );
3839 aHighlightChangedTimer.SetTimeout( GetSettings().GetMouseSettings().GetMenuDelay() );
3840 aSubmenuCloseTimer.SetTimeout( GetSettings().GetMouseSettings().GetMenuDelay() );
3841 aSubmenuCloseTimer.SetTimeoutHdl( LINK( this, MenuFloatingWindow, SubmenuClose ) );
3842 aScrollTimer.SetTimeoutHdl( LINK( this, MenuFloatingWindow, AutoScroll ) );
3844 AddEventListener( LINK( this, MenuFloatingWindow, ShowHideListener ) );
3847 void MenuFloatingWindow::doShutdown()
3849 if( pMenu )
3851 // #105373# notify toolkit that highlight was removed
3852 // otherwise the entry will not be read when the menu is opened again
3853 if( nHighlightedItem != ITEMPOS_INVALID )
3854 pMenu->ImplCallEventListeners( VCLEVENT_MENU_DEHIGHLIGHT, nHighlightedItem );
3856 if( !bKeyInput && pMenu && pMenu->pStartedFrom && !pMenu->pStartedFrom->bIsMenuBar )
3858 // #102461# remove highlight in parent
3859 MenuItemData* pData;
3860 USHORT i, nCount = (USHORT)pMenu->pStartedFrom->pItemList->Count();
3861 for(i = 0; i < nCount; i++)
3863 pData = pMenu->pStartedFrom->pItemList->GetDataFromPos( i );
3864 if( pData && ( pData->pSubMenu == pMenu ) )
3865 break;
3867 if( i < nCount )
3869 MenuFloatingWindow* pPWin = (MenuFloatingWindow*)pMenu->pStartedFrom->ImplGetWindow();
3870 if( pPWin )
3871 pPWin->HighlightItem( i, FALSE );
3875 // free the reference to the accessible component
3876 SetAccessible( ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible >() );
3878 aHighlightChangedTimer.Stop();
3880 // #95056# invalidate screen area covered by system window
3881 // so this can be taken into account if the commandhandler performs a scroll operation
3882 if( GetParent() )
3884 Rectangle aInvRect( GetWindowExtentsRelative( GetParent() ) );
3885 GetParent()->Invalidate( aInvRect );
3887 pMenu = NULL;
3888 RemoveEventListener( LINK( this, MenuFloatingWindow, ShowHideListener ) );
3892 MenuFloatingWindow::~MenuFloatingWindow()
3894 doShutdown();
3897 void MenuFloatingWindow::Resize()
3899 ImplInitClipRegion();
3902 long MenuFloatingWindow::ImplGetStartY() const
3904 long nY = 0;
3905 if( pMenu )
3907 for ( USHORT n = 0; n < nFirstEntry; n++ )
3908 nY += pMenu->GetItemList()->GetDataFromPos( n )->aSz.Height();
3910 return -nY;
3913 Region MenuFloatingWindow::ImplCalcClipRegion( BOOL bIncludeLogo ) const
3915 Size aOutSz = GetOutputSizePixel();
3916 Point aPos;
3917 Rectangle aRect( aPos, aOutSz );
3918 aRect.Top() += nScrollerHeight;
3919 aRect.Bottom() -= nScrollerHeight;
3921 if ( pMenu && pMenu->pLogo && !bIncludeLogo )
3922 aRect.Left() += pMenu->pLogo->aBitmap.GetSizePixel().Width();
3924 Region aRegion = aRect;
3925 if ( pMenu && pMenu->pLogo && bIncludeLogo && nScrollerHeight )
3926 aRegion.Union( Rectangle( Point(), Size( pMenu->pLogo->aBitmap.GetSizePixel().Width(), aOutSz.Height() ) ) );
3928 return aRegion;
3931 void MenuFloatingWindow::ImplInitClipRegion()
3933 if ( IsScrollMenu() )
3935 SetClipRegion( ImplCalcClipRegion() );
3937 else
3939 SetClipRegion();
3943 void MenuFloatingWindow::ImplHighlightItem( const MouseEvent& rMEvt, BOOL bMBDown )
3945 if( ! pMenu )
3946 return;
3948 long nY = nScrollerHeight;
3949 long nMouseY = rMEvt.GetPosPixel().Y();
3950 Size aOutSz = GetOutputSizePixel();
3951 if ( ( nMouseY >= nY ) && ( nMouseY < ( aOutSz.Height() - nY ) ) )
3953 BOOL bHighlighted = FALSE;
3954 USHORT nCount = (USHORT)pMenu->pItemList->Count();
3955 nY += ImplGetStartY(); // ggf. gescrollt.
3956 for ( USHORT n = 0; !bHighlighted && ( n < nCount ); n++ )
3958 if ( pMenu->ImplIsVisible( n ) )
3960 MenuItemData* pItemData = pMenu->pItemList->GetDataFromPos( n );
3961 long nOldY = nY;
3962 nY += pItemData->aSz.Height();
3963 if ( ( nOldY <= nMouseY ) && ( nY > nMouseY ) && pMenu->ImplIsSelectable( n ) )
3965 BOOL bPopupArea = TRUE;
3966 if ( pItemData->nBits & MIB_POPUPSELECT )
3968 // Nur wenn ueber dem Pfeil geklickt wurde...
3969 Size aSz = GetOutputSizePixel();
3970 long nFontHeight = GetTextHeight();
3971 bPopupArea = ( rMEvt.GetPosPixel().X() >= ( aSz.Width() - nFontHeight - nFontHeight/4 ) );
3974 if ( bMBDown )
3976 if ( n != nHighlightedItem )
3978 ChangeHighlightItem( (USHORT)n, FALSE );
3981 BOOL bAllowNewPopup = TRUE;
3982 if ( pActivePopup )
3984 MenuItemData* pData = pMenu->pItemList->GetDataFromPos( n );
3985 bAllowNewPopup = pData && ( pData->pSubMenu != pActivePopup );
3986 if ( bAllowNewPopup )
3987 KillActivePopup();
3990 if ( bPopupArea && bAllowNewPopup )
3992 HighlightChanged( NULL );
3995 else
3997 if ( n != nHighlightedItem )
3999 ChangeHighlightItem( (USHORT)n, TRUE );
4001 else if ( pItemData->nBits & MIB_POPUPSELECT )
4003 if ( bPopupArea && ( pActivePopup != pItemData->pSubMenu ) )
4004 HighlightChanged( NULL );
4007 bHighlighted = TRUE;
4011 if ( !bHighlighted )
4012 ChangeHighlightItem( ITEMPOS_INVALID, TRUE );
4014 else
4016 ImplScroll( rMEvt.GetPosPixel() );
4017 ChangeHighlightItem( ITEMPOS_INVALID, TRUE );
4021 IMPL_LINK( MenuFloatingWindow, PopupEnd, FloatingWindow*, EMPTYARG )
4023 // "this" will be deleted before the end of this method!
4024 Menu* pM = pMenu;
4025 if ( bInExecute )
4027 if ( pActivePopup )
4029 //DBG_ASSERT( !pActivePopup->ImplGetWindow(), "PopupEnd, obwohl pActivePopup MIT Window!" );
4030 KillActivePopup(); // should be ok to just remove it
4031 //pActivePopup->bCanceled = TRUE;
4033 bInExecute = FALSE;
4034 pMenu->bInCallback = TRUE;
4035 pMenu->Deactivate();
4036 pMenu->bInCallback = FALSE;
4038 else
4040 if( pMenu )
4042 // Wenn dies Fenster von TH geschlossen wurde, hat noch ein anderes
4043 // Menu dieses Fenster als pActivePopup.
4044 if ( pMenu->pStartedFrom )
4046 // Das pWin am 'Parent' kann aber schon 0 sein, falls die Kette von
4047 // vorne abgeraeumt wurde und jetzt die EndPopup-Events eintrudeln
4048 if ( pMenu->pStartedFrom->bIsMenuBar )
4050 MenuBarWindow* p = (MenuBarWindow*) pMenu->pStartedFrom->ImplGetWindow();
4051 if ( p )
4052 p->PopupClosed( pMenu );
4054 else
4056 MenuFloatingWindow* p = (MenuFloatingWindow*) pMenu->pStartedFrom->ImplGetWindow();
4057 if ( p )
4058 p->KillActivePopup( (PopupMenu*)pMenu );
4064 if ( pM )
4065 pM->pStartedFrom = 0;
4067 return 0;
4070 IMPL_LINK( MenuFloatingWindow, AutoScroll, Timer*, EMPTYARG )
4072 ImplScroll( GetPointerPosPixel() );
4073 return 1;
4076 IMPL_LINK( MenuFloatingWindow, HighlightChanged, Timer*, pTimer )
4078 if( ! pMenu )
4079 return 0;
4081 MenuItemData* pItemData = pMenu->pItemList->GetDataFromPos( nHighlightedItem );
4082 if ( pItemData )
4084 if ( pActivePopup && ( pActivePopup != pItemData->pSubMenu ) )
4086 ULONG nOldFlags = GetPopupModeFlags();
4087 SetPopupModeFlags( GetPopupModeFlags() | FLOATWIN_POPUPMODE_NOAPPFOCUSCLOSE );
4088 KillActivePopup();
4089 SetPopupModeFlags( nOldFlags );
4091 if ( pItemData->bEnabled && pItemData->pSubMenu && pItemData->pSubMenu->GetItemCount() && ( pItemData->pSubMenu != pActivePopup ) )
4093 pActivePopup = (PopupMenu*)pItemData->pSubMenu;
4094 long nY = nScrollerHeight+ImplGetStartY();
4095 MenuItemData* pData = 0;
4096 for ( ULONG n = 0; n < nHighlightedItem; n++ )
4098 pData = pMenu->pItemList->GetDataFromPos( n );
4099 nY += pData->aSz.Height();
4101 pData = pMenu->pItemList->GetDataFromPos( nHighlightedItem );
4102 Size MySize = GetOutputSizePixel();
4103 // Point MyPos = GetPosPixel();
4104 // Point aItemTopLeft( MyPos.X(), MyPos.Y()+nY );
4105 Point aItemTopLeft( 0, nY );
4106 Point aItemBottomRight( aItemTopLeft );
4107 aItemBottomRight.X() += MySize.Width();
4108 aItemBottomRight.Y() += pData->aSz.Height();
4110 // Popups leicht versetzen:
4111 aItemTopLeft.X() += 2;
4112 aItemBottomRight.X() -= 2;
4113 if ( nHighlightedItem )
4114 aItemTopLeft.Y() -= 2;
4115 else
4117 sal_Int32 nL, nT, nR, nB;
4118 GetBorder( nL, nT, nR, nB );
4119 aItemTopLeft.Y() -= nT;
4122 // pTest: Wegen Abstuerzen durch Reschedule() im Aufruf von Activate()
4123 // Ausserdem wird damit auch verhindert, dass SubMenus angezeigt werden,
4124 // die lange im Activate Rescheduled haben und jetzt schon nicht mehr
4125 // angezeigt werden sollen.
4126 Menu* pTest = pActivePopup;
4127 ULONG nOldFlags = GetPopupModeFlags();
4128 SetPopupModeFlags( GetPopupModeFlags() | FLOATWIN_POPUPMODE_NOAPPFOCUSCLOSE );
4129 USHORT nRet = pActivePopup->ImplExecute( this, Rectangle( aItemTopLeft, aItemBottomRight ), FLOATWIN_POPUPMODE_RIGHT, pMenu, pTimer ? FALSE : TRUE );
4130 SetPopupModeFlags( nOldFlags );
4132 // nRet != 0, wenn es waerend Activate() abgeschossen wurde...
4133 if ( !nRet && ( pActivePopup == pTest ) && pActivePopup->ImplGetWindow() )
4134 pActivePopup->ImplGetFloatingWindow()->AddPopupModeWindow( this );
4138 return 0;
4141 IMPL_LINK( MenuFloatingWindow, SubmenuClose, Timer*, EMPTYARG )
4143 if( pMenu && pMenu->pStartedFrom )
4145 MenuFloatingWindow* pWin = (MenuFloatingWindow*) pMenu->pStartedFrom->GetWindow();
4146 if( pWin )
4147 pWin->KillActivePopup();
4149 return 0;
4152 IMPL_LINK( MenuFloatingWindow, ShowHideListener, VclWindowEvent*, pEvent )
4154 if( ! pMenu )
4155 return 0;
4157 if( pEvent->GetId() == VCLEVENT_WINDOW_SHOW )
4158 pMenu->ImplCallEventListeners( VCLEVENT_MENU_SHOW, ITEMPOS_INVALID );
4159 else if( pEvent->GetId() == VCLEVENT_WINDOW_HIDE )
4160 pMenu->ImplCallEventListeners( VCLEVENT_MENU_HIDE, ITEMPOS_INVALID );
4161 return 0;
4164 void MenuFloatingWindow::EnableScrollMenu( BOOL b )
4166 bScrollMenu = b;
4167 nScrollerHeight = b ? (USHORT) GetSettings().GetStyleSettings().GetScrollBarSize() /2 : 0;
4168 bScrollDown = TRUE;
4169 ImplInitClipRegion();
4172 void MenuFloatingWindow::Execute()
4174 ImplSVData* pSVData = ImplGetSVData();
4176 pSVData->maAppData.mpActivePopupMenu = (PopupMenu*)pMenu;
4178 bInExecute = TRUE;
4179 // bCallingSelect = FALSE;
4181 while ( bInExecute )
4182 Application::Yield();
4184 pSVData->maAppData.mpActivePopupMenu = NULL;
4186 // while ( bCallingSelect )
4187 // Application::Yield();
4190 void MenuFloatingWindow::StopExecute( ULONG nFocusId )
4192 // Focus wieder herstellen
4193 // (kann schon im Select wieder hergestellt wurden sein)
4194 if ( nSaveFocusId )
4196 Window::EndSaveFocus( nFocusId, FALSE );
4197 nFocusId = nSaveFocusId;
4198 if ( nFocusId )
4200 nSaveFocusId = 0;
4201 ImplGetSVData()->maWinData.mbNoDeactivate = FALSE;
4204 ImplEndPopupMode( 0, nFocusId );
4206 aHighlightChangedTimer.Stop();
4207 bInExecute = FALSE;
4208 if ( pActivePopup )
4210 KillActivePopup();
4212 // notify parent, needed for accessibility
4213 if( pMenu && pMenu->pStartedFrom )
4214 pMenu->pStartedFrom->ImplCallEventListeners( VCLEVENT_MENU_SUBMENUDEACTIVATE, nPosInParent );
4217 void MenuFloatingWindow::KillActivePopup( PopupMenu* pThisOnly )
4219 if ( pActivePopup && ( !pThisOnly || ( pThisOnly == pActivePopup ) ) )
4221 if( pActivePopup->pWindow != NULL )
4222 if( ((FloatingWindow *) pActivePopup->pWindow)->IsInCleanUp() )
4223 return; // kill it later
4224 if ( pActivePopup->bInCallback )
4225 pActivePopup->bCanceled = TRUE;
4227 // Vor allen Aktionen schon pActivePopup = 0, falls z.B.
4228 // PopupModeEndHdl des zu zerstoerenden Popups mal synchron gerufen wird.
4229 PopupMenu* pPopup = pActivePopup;
4230 pActivePopup = NULL;
4231 pPopup->bInCallback = TRUE;
4232 pPopup->Deactivate();
4233 pPopup->bInCallback = FALSE;
4234 if ( pPopup->ImplGetWindow() )
4236 pPopup->ImplGetFloatingWindow()->StopExecute();
4237 pPopup->ImplGetFloatingWindow()->doShutdown();
4238 pPopup->pWindow->doLazyDelete();
4239 pPopup->pWindow = NULL;
4241 Update();
4246 void MenuFloatingWindow::EndExecute()
4248 Menu* pStart = pMenu ? pMenu->ImplGetStartMenu() : NULL;
4249 ULONG nFocusId = 0;
4250 if ( pStart && pStart->bIsMenuBar )
4252 nFocusId = ((MenuBarWindow*)((MenuBar*)pStart)->ImplGetWindow())->GetFocusId();
4253 if ( nFocusId )
4255 ((MenuBarWindow*)((MenuBar*)pStart)->ImplGetWindow())->SetFocusId( 0 );
4256 ImplGetSVData()->maWinData.mbNoDeactivate = FALSE;
4260 // Wenn von woanders gestartet, dann ab dort aufraumen:
4261 MenuFloatingWindow* pCleanUpFrom = this;
4262 MenuFloatingWindow* pWin = this;
4263 while ( pWin && !pWin->bInExecute &&
4264 pWin->pMenu->pStartedFrom && !pWin->pMenu->pStartedFrom->bIsMenuBar )
4266 pWin = ((PopupMenu*)pWin->pMenu->pStartedFrom)->ImplGetFloatingWindow();
4268 if ( pWin )
4269 pCleanUpFrom = pWin;
4271 // Dies Fenster wird gleich zerstoert => Daten lokal merken...
4272 Menu* pM = pMenu;
4273 USHORT nItem = nHighlightedItem;
4275 pCleanUpFrom->StopExecute( nFocusId );
4277 if ( nItem != ITEMPOS_INVALID && pM )
4279 MenuItemData* pItemData = pM->GetItemList()->GetDataFromPos( nItem );
4280 if ( pItemData && !pItemData->bIsTemporary )
4282 pM->nSelectedId = pItemData->nId;
4283 if ( pStart )
4284 pStart->nSelectedId = pItemData->nId;
4286 pM->ImplSelect();
4291 void MenuFloatingWindow::EndExecute( USHORT nId )
4293 USHORT nPos;
4294 if ( pMenu && pMenu->GetItemList()->GetData( nId, nPos ) )
4295 nHighlightedItem = nPos;
4296 else
4297 nHighlightedItem = ITEMPOS_INVALID;
4299 EndExecute();
4302 void MenuFloatingWindow::MouseButtonDown( const MouseEvent& rMEvt )
4304 // TH macht ein ToTop auf dieses Fenster, aber das aktive Popup
4305 // soll oben bleiben...
4306 // due to focus chage this would close all menues -> don't do it (#94123)
4307 //if ( pActivePopup && pActivePopup->ImplGetWindow() && !pActivePopup->ImplGetFloatingWindow()->pActivePopup )
4308 // pActivePopup->ImplGetFloatingWindow()->ToTop( TOTOP_NOGRABFOCUS );
4310 ImplHighlightItem( rMEvt, TRUE );
4312 nMBDownPos = nHighlightedItem;
4315 void MenuFloatingWindow::MouseButtonUp( const MouseEvent& rMEvt )
4317 MenuItemData* pData = pMenu ? pMenu->GetItemList()->GetDataFromPos( nHighlightedItem ) : NULL;
4318 // nMBDownPos in lokaler Variable merken und gleich zuruecksetzen,
4319 // weil nach EndExecute zu spaet
4320 USHORT _nMBDownPos = nMBDownPos;
4321 nMBDownPos = ITEMPOS_INVALID;
4322 if ( pData && pData->bEnabled && ( pData->eType != MENUITEM_SEPARATOR ) )
4324 if ( !pData->pSubMenu )
4326 EndExecute();
4328 else if ( ( pData->nBits & MIB_POPUPSELECT ) && ( nHighlightedItem == _nMBDownPos ) && ( rMEvt.GetClicks() == 2 ) )
4330 // Nicht wenn ueber dem Pfeil geklickt wurde...
4331 Size aSz = GetOutputSizePixel();
4332 long nFontHeight = GetTextHeight();
4333 if ( rMEvt.GetPosPixel().X() < ( aSz.Width() - nFontHeight - nFontHeight/4 ) )
4334 EndExecute();
4340 void MenuFloatingWindow::MouseMove( const MouseEvent& rMEvt )
4342 if ( !IsVisible() || rMEvt.IsSynthetic() || rMEvt.IsEnterWindow() )
4343 return;
4345 if ( rMEvt.IsLeaveWindow() )
4347 #ifdef OS2
4348 if ( ImplHilite(rMEvt) )
4350 #endif
4351 // #102461# do not remove highlight if a popup menu is open at this position
4352 MenuItemData* pData = pMenu ? pMenu->pItemList->GetDataFromPos( nHighlightedItem ) : NULL;
4353 // close popup with some delayed if we leave somewhere else
4354 if( pActivePopup && pData && pData->pSubMenu != pActivePopup )
4355 pActivePopup->ImplGetFloatingWindow()->aSubmenuCloseTimer.Start();
4357 if( !pActivePopup || (pData && pData->pSubMenu != pActivePopup ) )
4358 ChangeHighlightItem( ITEMPOS_INVALID, FALSE );
4359 #ifdef OS2
4361 #endif
4363 if ( IsScrollMenu() )
4364 ImplScroll( rMEvt.GetPosPixel() );
4366 else
4367 #ifdef OS2
4368 if ( ImplHilite(rMEvt) )
4369 #endif
4371 aSubmenuCloseTimer.Stop();
4372 if( bIgnoreFirstMove )
4373 bIgnoreFirstMove = FALSE;
4374 else
4375 ImplHighlightItem( rMEvt, FALSE );
4379 void MenuFloatingWindow::ImplScroll( BOOL bUp )
4381 KillActivePopup();
4382 Update();
4384 if( ! pMenu )
4385 return;
4387 HighlightItem( nHighlightedItem, FALSE );
4389 pMenu->ImplKillLayoutData();
4391 if ( bScrollUp && bUp )
4393 nFirstEntry = pMenu->ImplGetPrevVisible( nFirstEntry );
4394 DBG_ASSERT( nFirstEntry != ITEMPOS_INVALID, "Scroll?!" );
4396 long nScrollEntryHeight = pMenu->GetItemList()->GetDataFromPos( nFirstEntry )->aSz.Height();
4398 // nStartY += nEntryHeight;
4400 if ( !bScrollDown )
4402 bScrollDown = TRUE;
4403 ImplDrawScroller( FALSE );
4406 if ( pMenu->ImplGetPrevVisible( nFirstEntry ) == ITEMPOS_INVALID )
4408 bScrollUp = FALSE;
4409 ImplDrawScroller( TRUE );
4412 Scroll( 0, nScrollEntryHeight, ImplCalcClipRegion( FALSE ).GetBoundRect(), SCROLL_CLIP );
4414 else if ( bScrollDown && !bUp )
4416 long nScrollEntryHeight = pMenu->GetItemList()->GetDataFromPos( nFirstEntry )->aSz.Height();
4418 nFirstEntry = pMenu->ImplGetNextVisible( nFirstEntry );
4419 DBG_ASSERT( nFirstEntry != ITEMPOS_INVALID, "Scroll?!" );
4422 if ( !bScrollUp )
4424 bScrollUp = TRUE;
4425 ImplDrawScroller( TRUE );
4428 long nHeight = GetOutputSizePixel().Height();
4429 USHORT nLastVisible;
4430 ((PopupMenu*)pMenu)->ImplCalcVisEntries( nHeight, nFirstEntry, &nLastVisible );
4431 if ( pMenu->ImplGetNextVisible( nLastVisible ) == ITEMPOS_INVALID )
4433 bScrollDown = FALSE;
4434 ImplDrawScroller( FALSE );
4437 // nStartY -= nEntryHeight;
4438 Scroll( 0, -nScrollEntryHeight, ImplCalcClipRegion( FALSE ).GetBoundRect(), SCROLL_CLIP );
4441 HighlightItem( nHighlightedItem, TRUE );
4444 void MenuFloatingWindow::ImplScroll( const Point& rMousePos )
4446 Size aOutSz = GetOutputSizePixel();
4448 long nY = nScrollerHeight;
4449 long nMouseY = rMousePos.Y();
4450 long nDelta = 0;
4452 if ( bScrollUp && ( nMouseY < nY ) )
4454 ImplScroll( TRUE );
4455 nDelta = nY - nMouseY;
4457 else if ( bScrollDown && ( nMouseY > ( aOutSz.Height() - nY ) ) )
4459 ImplScroll( FALSE );
4460 nDelta = nMouseY - ( aOutSz.Height() - nY );
4463 if ( nDelta )
4465 aScrollTimer.Stop(); // Falls durch MouseMove gescrollt.
4466 long nTimeout;
4467 if ( nDelta < 3 )
4468 nTimeout = 200;
4469 else if ( nDelta < 5 )
4470 nTimeout = 100;
4471 else if ( nDelta < 8 )
4472 nTimeout = 70;
4473 else if ( nDelta < 12 )
4474 nTimeout = 40;
4475 else
4476 nTimeout = 20;
4477 aScrollTimer.SetTimeout( nTimeout );
4478 aScrollTimer.Start();
4481 void MenuFloatingWindow::ChangeHighlightItem( USHORT n, BOOL bStartPopupTimer )
4483 // #57934# ggf. das aktive Popup sofort schliessen, damit TH's Hintergrundsicherung funktioniert.
4484 // #65750# Dann verzichten wir lieber auf den schmalen Streifen Hintergrundsicherung.
4485 // Sonst lassen sich die Menus schlecht bedienen.
4486 // MenuItemData* pNextData = pMenu->pItemList->GetDataFromPos( n );
4487 // if ( pActivePopup && pNextData && ( pActivePopup != pNextData->pSubMenu ) )
4488 // KillActivePopup();
4490 aSubmenuCloseTimer.Stop();
4491 if( ! pMenu )
4492 return;
4494 if ( nHighlightedItem != ITEMPOS_INVALID )
4496 HighlightItem( nHighlightedItem, FALSE );
4497 pMenu->ImplCallEventListeners( VCLEVENT_MENU_DEHIGHLIGHT, nHighlightedItem );
4500 nHighlightedItem = (USHORT)n;
4501 DBG_ASSERT( pMenu->ImplIsVisible( nHighlightedItem ) || nHighlightedItem == ITEMPOS_INVALID, "ChangeHighlightItem: Not visible!" );
4502 if( nHighlightedItem != ITEMPOS_INVALID )
4504 if( pMenu->pStartedFrom && !pMenu->pStartedFrom->bIsMenuBar )
4506 // #102461# make sure parent entry is highlighted as well
4507 MenuItemData* pData;
4508 USHORT i, nCount = (USHORT)pMenu->pStartedFrom->pItemList->Count();
4509 for(i = 0; i < nCount; i++)
4511 pData = pMenu->pStartedFrom->pItemList->GetDataFromPos( i );
4512 if( pData && ( pData->pSubMenu == pMenu ) )
4513 break;
4515 if( i < nCount )
4517 MenuFloatingWindow* pPWin = (MenuFloatingWindow*)pMenu->pStartedFrom->ImplGetWindow();
4518 if( pPWin && pPWin->nHighlightedItem != i )
4520 pPWin->HighlightItem( i, TRUE );
4521 pPWin->nHighlightedItem = i;
4525 HighlightItem( nHighlightedItem, TRUE );
4526 pMenu->ImplCallHighlight( nHighlightedItem );
4528 else
4529 pMenu->nSelectedId = 0;
4531 if ( bStartPopupTimer )
4533 // #102438# Menu items are not selectable
4534 // If a menu item is selected by an AT-tool via the XAccessibleAction, XAccessibleValue
4535 // or XAccessibleSelection interface, and the parent popup menus are not executed yet,
4536 // the parent popup menus must be executed SYNCHRONOUSLY, before the menu item is selected.
4537 if ( GetSettings().GetMouseSettings().GetMenuDelay() )
4538 aHighlightChangedTimer.Start();
4539 else
4540 HighlightChanged( &aHighlightChangedTimer );
4544 void MenuFloatingWindow::HighlightItem( USHORT nPos, BOOL bHighlight )
4546 if( ! pMenu )
4547 return;
4549 Size aSz = GetOutputSizePixel();
4550 long nStartY = ImplGetStartY();
4551 long nY = nScrollerHeight+nStartY;
4552 long nX = 0;
4554 if ( pMenu->pLogo )
4555 nX = pMenu->pLogo->aBitmap.GetSizePixel().Width();
4557 int nOuterSpace = ImplGetSVData()->maNWFData.mnMenuFormatExtraBorder;
4558 nY += nOuterSpace;
4560 USHORT nCount = (USHORT)pMenu->pItemList->Count();
4561 for ( USHORT n = 0; n < nCount; n++ )
4563 MenuItemData* pData = pMenu->pItemList->GetDataFromPos( n );
4564 if ( n == nPos )
4566 DBG_ASSERT( pMenu->ImplIsVisible( n ), "Highlight: Item not visible!" );
4567 if ( pData->eType != MENUITEM_SEPARATOR )
4569 BOOL bRestoreLineColor = FALSE;
4570 Color oldLineColor;
4571 bool bDrawItemRect = true;
4573 Rectangle aItemRect( Point( nX+nOuterSpace, nY ), Size( aSz.Width()-2*nOuterSpace, pData->aSz.Height() ) );
4574 if ( pData->nBits & MIB_POPUPSELECT )
4576 long nFontHeight = GetTextHeight();
4577 aItemRect.Right() -= nFontHeight + nFontHeight/4;
4580 if( IsNativeControlSupported( CTRL_MENU_POPUP, PART_ENTIRE_CONTROL ) )
4582 Size aPxSize( GetOutputSizePixel() );
4583 Push( PUSH_CLIPREGION );
4584 IntersectClipRegion( Rectangle( Point( nX, nY ), Size( aSz.Width(), pData->aSz.Height() ) ) );
4585 Rectangle aCtrlRect( Point( nX, 0 ), Size( aPxSize.Width()-nX, aPxSize.Height() ) );
4586 DrawNativeControl( CTRL_MENU_POPUP, PART_ENTIRE_CONTROL,
4587 Region( aCtrlRect ),
4588 CTRL_STATE_ENABLED,
4589 ImplControlValue(),
4590 OUString() );
4591 if( bHighlight &&
4592 IsNativeControlSupported( CTRL_MENU_POPUP, PART_MENU_ITEM ) )
4594 bDrawItemRect = false;
4595 if( FALSE == DrawNativeControl( CTRL_MENU_POPUP, PART_MENU_ITEM,
4596 Region( aItemRect ),
4597 CTRL_STATE_SELECTED | ( pData->bEnabled? CTRL_STATE_ENABLED: 0 ),
4598 ImplControlValue(),
4599 OUString() ) )
4601 bDrawItemRect = bHighlight;
4604 else
4605 bDrawItemRect = bHighlight;
4606 Pop();
4608 if( bDrawItemRect )
4610 if ( bHighlight )
4612 if( pData->bEnabled )
4613 SetFillColor( GetSettings().GetStyleSettings().GetMenuHighlightColor() );
4614 else
4616 SetFillColor();
4617 oldLineColor = GetLineColor();
4618 SetLineColor( GetSettings().GetStyleSettings().GetMenuHighlightColor() );
4619 bRestoreLineColor = TRUE;
4622 else
4623 SetFillColor( GetSettings().GetStyleSettings().GetMenuColor() );
4625 DrawRect( aItemRect );
4627 pMenu->ImplPaint( this, nScrollerHeight, nStartY, pData, bHighlight );
4628 if( bRestoreLineColor )
4629 SetLineColor( oldLineColor );
4631 return;
4634 nY += pData->aSz.Height();
4638 Rectangle MenuFloatingWindow::ImplGetItemRect( USHORT nPos )
4640 if( ! pMenu )
4641 return Rectangle();
4643 Rectangle aRect;
4644 Size aSz = GetOutputSizePixel();
4645 long nStartY = ImplGetStartY();
4646 long nY = nScrollerHeight+nStartY;
4647 long nX = 0;
4649 if ( pMenu->pLogo )
4650 nX = pMenu->pLogo->aBitmap.GetSizePixel().Width();
4652 USHORT nCount = (USHORT)pMenu->pItemList->Count();
4653 for ( USHORT n = 0; n < nCount; n++ )
4655 MenuItemData* pData = pMenu->pItemList->GetDataFromPos( n );
4656 if ( n == nPos )
4658 DBG_ASSERT( pMenu->ImplIsVisible( n ), "ImplGetItemRect: Item not visible!" );
4659 if ( pData->eType != MENUITEM_SEPARATOR )
4661 aRect = Rectangle( Point( nX, nY ), Size( aSz.Width(), pData->aSz.Height() ) );
4662 if ( pData->nBits & MIB_POPUPSELECT )
4664 long nFontHeight = GetTextHeight();
4665 aRect.Right() -= nFontHeight + nFontHeight/4;
4668 break;
4670 nY += pData->aSz.Height();
4672 return aRect;
4676 void MenuFloatingWindow::ImplCursorUpDown( BOOL bUp, BOOL bHomeEnd )
4678 if( ! pMenu )
4679 return;
4681 const StyleSettings& rSettings = GetSettings().GetStyleSettings();
4683 USHORT n = nHighlightedItem;
4684 if ( n == ITEMPOS_INVALID )
4686 if ( bUp )
4687 n = 0;
4688 else
4689 n = pMenu->GetItemCount()-1;
4692 USHORT nLoop = n;
4694 if( bHomeEnd )
4696 // absolute positioning
4697 if( bUp )
4699 n = pMenu->GetItemCount();
4700 nLoop = n-1;
4702 else
4704 n = (USHORT)-1;
4705 nLoop = n+1;
4711 if ( bUp )
4713 if ( n )
4714 n--;
4715 else
4716 if ( !IsScrollMenu() || ( nHighlightedItem == ITEMPOS_INVALID ) )
4717 n = pMenu->GetItemCount()-1;
4718 else
4719 break;
4721 else
4723 n++;
4724 if ( n >= pMenu->GetItemCount() )
4726 if ( !IsScrollMenu() || ( nHighlightedItem == ITEMPOS_INVALID ) )
4727 n = 0;
4728 else
4729 break;
4733 MenuItemData* pData = (MenuItemData*)pMenu->GetItemList()->GetDataFromPos( n );
4734 if ( ( pData->bEnabled || !rSettings.GetSkipDisabledInMenus() )
4735 && ( pData->eType != MENUITEM_SEPARATOR ) && pMenu->ImplIsVisible( n ) && pMenu->ImplIsSelectable( n ) )
4737 // Selektion noch im sichtbaren Bereich?
4738 if ( IsScrollMenu() )
4740 ChangeHighlightItem( ITEMPOS_INVALID, FALSE );
4742 while ( n < nFirstEntry )
4743 ImplScroll( TRUE );
4745 Size aOutSz = GetOutputSizePixel();
4746 USHORT nLastVisible;
4747 ((PopupMenu*)pMenu)->ImplCalcVisEntries( aOutSz.Height(), nFirstEntry, &nLastVisible );
4748 while ( n > nLastVisible )
4750 ImplScroll( FALSE );
4751 ((PopupMenu*)pMenu)->ImplCalcVisEntries( aOutSz.Height(), nFirstEntry, &nLastVisible );
4754 ChangeHighlightItem( n, FALSE );
4755 break;
4757 } while ( n != nLoop );
4760 void MenuFloatingWindow::KeyInput( const KeyEvent& rKEvent )
4762 ImplDelData aDelData;
4763 ImplAddDel( &aDelData );
4765 USHORT nCode = rKEvent.GetKeyCode().GetCode();
4766 bKeyInput = TRUE;
4767 switch ( nCode )
4769 case KEY_UP:
4770 case KEY_DOWN:
4772 ImplCursorUpDown( nCode == KEY_UP );
4774 break;
4775 case KEY_END:
4776 case KEY_HOME:
4778 ImplCursorUpDown( nCode == KEY_END, TRUE );
4780 break;
4781 case KEY_F6:
4782 case KEY_ESCAPE:
4784 // Ctrl-F6 acts like ESC here, the menu bar however will then put the focus in the document
4785 if( nCode == KEY_F6 && !rKEvent.GetKeyCode().IsMod1() )
4786 break;
4787 if( pMenu )
4789 if ( !pMenu->pStartedFrom )
4791 StopExecute();
4792 KillActivePopup();
4794 else if ( pMenu->pStartedFrom->bIsMenuBar )
4796 // Forward...
4797 ((MenuBarWindow*)((MenuBar*)pMenu->pStartedFrom)->ImplGetWindow())->KeyInput( rKEvent );
4799 else
4801 StopExecute();
4802 PopupMenu* pPopupMenu = (PopupMenu*)pMenu->pStartedFrom;
4803 MenuFloatingWindow* pFloat = pPopupMenu->ImplGetFloatingWindow();
4804 pFloat->GrabFocus();
4805 pFloat->KillActivePopup();
4806 pPopupMenu->ImplCallHighlight(pFloat->nHighlightedItem);
4810 break;
4811 case KEY_LEFT:
4813 if ( pMenu && pMenu->pStartedFrom )
4815 StopExecute();
4816 if ( pMenu->pStartedFrom->bIsMenuBar )
4818 // Forward...
4819 ((MenuBarWindow*)((MenuBar*)pMenu->pStartedFrom)->ImplGetWindow())->KeyInput( rKEvent );
4821 else
4823 MenuFloatingWindow* pFloat = ((PopupMenu*)pMenu->pStartedFrom)->ImplGetFloatingWindow();
4824 pFloat->GrabFocus();
4825 pFloat->KillActivePopup();
4829 break;
4830 case KEY_RIGHT:
4832 if( pMenu )
4834 BOOL bDone = FALSE;
4835 if ( nHighlightedItem != ITEMPOS_INVALID )
4837 MenuItemData* pData = pMenu->GetItemList()->GetDataFromPos( nHighlightedItem );
4838 if ( pData && pData->pSubMenu )
4840 HighlightChanged( 0 );
4841 bDone = TRUE;
4844 if ( !bDone )
4846 Menu* pStart = pMenu->ImplGetStartMenu();
4847 if ( pStart && pStart->bIsMenuBar )
4849 // Forward...
4850 pStart->ImplGetWindow()->KeyInput( rKEvent );
4855 break;
4856 case KEY_RETURN:
4858 if( pMenu )
4860 MenuItemData* pData = pMenu->GetItemList()->GetDataFromPos( nHighlightedItem );
4861 if ( pData && pData->bEnabled )
4863 if ( pData->pSubMenu )
4864 HighlightChanged( 0 );
4865 else
4866 EndExecute();
4868 else
4869 StopExecute();
4872 break;
4873 case KEY_MENU:
4875 if( pMenu )
4877 Menu* pStart = pMenu->ImplGetStartMenu();
4878 if ( pStart && pStart->bIsMenuBar )
4880 // Forward...
4881 pStart->ImplGetWindow()->KeyInput( rKEvent );
4885 break;
4886 default:
4888 xub_Unicode nCharCode = rKEvent.GetCharCode();
4889 USHORT nPos = 0;
4890 USHORT nDuplicates = 0;
4891 MenuItemData* pData = (nCharCode && pMenu) ? pMenu->GetItemList()->SearchItem( nCharCode, rKEvent.GetKeyCode(), nPos, nDuplicates, nHighlightedItem ) : NULL;
4892 if ( pData )
4894 if ( pData->pSubMenu || nDuplicates > 1 )
4896 ChangeHighlightItem( nPos, FALSE );
4897 HighlightChanged( 0 );
4899 else
4901 nHighlightedItem = nPos;
4902 EndExecute();
4905 else
4907 // Bei ungueltigen Tasten Beepen, aber nicht bei HELP und F-Tasten
4908 if ( !rKEvent.GetKeyCode().IsMod2() && ( nCode != KEY_HELP ) && ( rKEvent.GetKeyCode().GetGroup() != KEYGROUP_FKEYS ) )
4909 Sound::Beep();
4910 FloatingWindow::KeyInput( rKEvent );
4914 // #105474# check if menu window was not destroyed
4915 if ( !aDelData.IsDelete() )
4917 ImplRemoveDel( &aDelData );
4918 bKeyInput = FALSE;
4922 void MenuFloatingWindow::Paint( const Rectangle& )
4924 if( ! pMenu )
4925 return;
4927 if( IsNativeControlSupported( CTRL_MENU_POPUP, PART_ENTIRE_CONTROL ) )
4929 SetClipRegion();
4930 long nX = pMenu->pLogo ? pMenu->pLogo->aBitmap.GetSizePixel().Width() : 0;
4931 Size aPxSize( GetOutputSizePixel() );
4932 aPxSize.Width() -= nX;
4933 DrawNativeControl( CTRL_MENU_POPUP, PART_ENTIRE_CONTROL,
4934 Region( Rectangle( Point( nX, 0 ), aPxSize ) ),
4935 CTRL_STATE_ENABLED,
4936 ImplControlValue(),
4937 OUString() );
4938 ImplInitClipRegion();
4940 if ( IsScrollMenu() )
4942 ImplDrawScroller( TRUE );
4943 ImplDrawScroller( FALSE );
4945 SetFillColor( GetSettings().GetStyleSettings().GetMenuColor() );
4946 pMenu->ImplPaint( this, nScrollerHeight, ImplGetStartY() );
4947 if ( nHighlightedItem != ITEMPOS_INVALID )
4948 HighlightItem( nHighlightedItem, TRUE );
4951 void MenuFloatingWindow::ImplDrawScroller( BOOL bUp )
4953 if( ! pMenu )
4954 return;
4956 SetClipRegion();
4958 Size aOutSz = GetOutputSizePixel();
4959 long nY = bUp ? 0 : ( aOutSz.Height() - nScrollerHeight );
4960 long nX = pMenu->pLogo ? pMenu->pLogo->aBitmap.GetSizePixel().Width() : 0;
4961 Rectangle aRect( Point( nX, nY ), Size( aOutSz.Width()-nX, nScrollerHeight ) );
4963 DecorationView aDecoView( this );
4964 SymbolType eSymbol = bUp ? SYMBOL_SPIN_UP : SYMBOL_SPIN_DOWN;
4966 USHORT nStyle = 0;
4967 if ( ( bUp && !bScrollUp ) || ( !bUp && !bScrollDown ) )
4968 nStyle |= SYMBOL_DRAW_DISABLE;
4970 aDecoView.DrawSymbol( aRect, eSymbol, GetSettings().GetStyleSettings().GetButtonTextColor(), nStyle );
4972 ImplInitClipRegion();
4975 void MenuFloatingWindow::RequestHelp( const HelpEvent& rHEvt )
4977 USHORT nId = nHighlightedItem;
4978 Menu* pM = pMenu;
4979 Window* pW = this;
4981 // #102618# Get item rect before destroying the window in EndExecute() call
4982 Rectangle aHighlightRect( ImplGetItemRect( nHighlightedItem ) );
4984 if ( rHEvt.GetMode() & (HELPMODE_CONTEXT | HELPMODE_EXTENDED) )
4986 nHighlightedItem = ITEMPOS_INVALID;
4987 EndExecute();
4988 pW = NULL;
4991 if( !ImplHandleHelpEvent( pW, pM, nId, rHEvt, aHighlightRect ) )
4992 Window::RequestHelp( rHEvt );
4995 void MenuFloatingWindow::StateChanged( StateChangedType nType )
4997 FloatingWindow::StateChanged( nType );
4999 if ( ( nType == STATE_CHANGE_CONTROLFOREGROUND ) || ( nType == STATE_CHANGE_CONTROLBACKGROUND ) )
5001 ImplInitMenuWindow( this, FALSE, FALSE );
5002 Invalidate();
5006 void MenuFloatingWindow::DataChanged( const DataChangedEvent& rDCEvt )
5008 FloatingWindow::DataChanged( rDCEvt );
5010 if ( (rDCEvt.GetType() == DATACHANGED_FONTS) ||
5011 (rDCEvt.GetType() == DATACHANGED_FONTSUBSTITUTION) ||
5012 ((rDCEvt.GetType() == DATACHANGED_SETTINGS) &&
5013 (rDCEvt.GetFlags() & SETTINGS_STYLE)) )
5015 ImplInitMenuWindow( this, FALSE, FALSE );
5016 Invalidate();
5020 void MenuFloatingWindow::Command( const CommandEvent& rCEvt )
5022 if ( rCEvt.GetCommand() == COMMAND_WHEEL )
5024 const CommandWheelData* pData = rCEvt.GetWheelData();
5025 if( !pData->GetModifier() && ( pData->GetMode() == COMMAND_WHEEL_SCROLL ) )
5027 // ImplCursorUpDown( pData->GetDelta() > 0L );
5028 ImplScroll( pData->GetDelta() > 0L );
5029 MouseMove( MouseEvent( GetPointerPosPixel(), 0 ) );
5034 ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible > MenuFloatingWindow::CreateAccessible()
5036 ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible > xAcc;
5038 if ( pMenu && !pMenu->pStartedFrom )
5039 xAcc = pMenu->GetAccessible();
5041 return xAcc;
5044 MenuBarWindow::MenuBarWindow( Window* pParent ) :
5045 Window( pParent, 0 ),
5046 aCloser( this ),
5047 aFloatBtn( this, WB_NOPOINTERFOCUS | WB_SMALLSTYLE | WB_RECTSTYLE ),
5048 aHideBtn( this, WB_NOPOINTERFOCUS | WB_SMALLSTYLE | WB_RECTSTYLE )
5050 SetType( WINDOW_MENUBARWINDOW );
5051 pMenu = NULL;
5052 pActivePopup = NULL;
5053 nSaveFocusId = 0;
5054 nHighlightedItem = ITEMPOS_INVALID;
5055 mbAutoPopup = TRUE;
5056 nSaveFocusId = 0;
5057 bIgnoreFirstMove = TRUE;
5058 bStayActive = FALSE;
5060 ResMgr* pResMgr = ImplGetResMgr();
5062 if( pResMgr )
5064 BitmapEx aBitmap( ResId( SV_RESID_BITMAP_CLOSEDOC, *pResMgr ) );
5065 BitmapEx aBitmapHC( ResId( SV_RESID_BITMAP_CLOSEDOCHC, *pResMgr ) );
5067 aCloser.maImage = Image( aBitmap );
5068 aCloser.maImageHC = Image( aBitmapHC );
5070 aCloser.SetOutStyle( TOOLBOX_STYLE_FLAT );
5071 aCloser.SetBackground();
5072 aCloser.SetPaintTransparent( TRUE );
5073 aCloser.SetParentClipMode( PARENTCLIPMODE_NOCLIP );
5075 aCloser.InsertItem( IID_DOCUMENTCLOSE,
5076 GetSettings().GetStyleSettings().GetMenuBarColor().IsDark() ? aCloser.maImageHC : aCloser.maImage, 0 );
5077 aCloser.SetSelectHdl( LINK( this, MenuBarWindow, CloserHdl ) );
5078 aCloser.AddEventListener( LINK( this, MenuBarWindow, ToolboxEventHdl ) );
5079 aCloser.SetQuickHelpText( IID_DOCUMENTCLOSE, XubString( ResId( SV_HELPTEXT_CLOSEDOCUMENT, *pResMgr ) ) );
5081 aFloatBtn.SetClickHdl( LINK( this, MenuBarWindow, FloatHdl ) );
5082 aFloatBtn.SetSymbol( SYMBOL_FLOAT );
5083 aFloatBtn.SetQuickHelpText( XubString( ResId( SV_HELPTEXT_RESTORE, *pResMgr ) ) );
5085 aHideBtn.SetClickHdl( LINK( this, MenuBarWindow, HideHdl ) );
5086 aHideBtn.SetSymbol( SYMBOL_HIDE );
5087 aHideBtn.SetQuickHelpText( XubString( ResId( SV_HELPTEXT_MINIMIZE, *pResMgr ) ) );
5090 ImplInitStyleSettings();
5092 AddEventListener( LINK( this, MenuBarWindow, ShowHideListener ) );
5095 MenuBarWindow::~MenuBarWindow()
5097 aCloser.RemoveEventListener( LINK( this, MenuBarWindow, ToolboxEventHdl ) );
5098 RemoveEventListener( LINK( this, MenuBarWindow, ShowHideListener ) );
5101 void MenuBarWindow::SetMenu( MenuBar* pMen )
5103 pMenu = pMen;
5104 KillActivePopup();
5105 nHighlightedItem = ITEMPOS_INVALID;
5106 ImplInitMenuWindow( this, TRUE, TRUE );
5107 if ( pMen )
5109 aCloser.ShowItem( IID_DOCUMENTCLOSE, pMen->HasCloser() );
5110 aCloser.Show( pMen->HasCloser() || !m_aAddButtons.empty() );
5111 aFloatBtn.Show( pMen->HasFloatButton() );
5112 aHideBtn.Show( pMen->HasHideButton() );
5114 Invalidate();
5116 // show and connect native menubar
5117 if( pMenu && pMenu->ImplGetSalMenu() )
5119 if( pMenu->ImplGetSalMenu()->VisibleMenuBar() )
5120 ImplGetFrame()->SetMenu( pMenu->ImplGetSalMenu() );
5122 pMenu->ImplGetSalMenu()->SetFrame( ImplGetFrame() );
5126 void MenuBarWindow::ShowButtons( BOOL bClose, BOOL bFloat, BOOL bHide )
5128 aCloser.ShowItem( IID_DOCUMENTCLOSE, bClose );
5129 aCloser.Show( bClose || ! m_aAddButtons.empty() );
5130 aFloatBtn.Show( bFloat );
5131 aHideBtn.Show( bHide );
5132 Resize();
5135 Size MenuBarWindow::MinCloseButtonSize()
5137 return aCloser.getMinSize();
5140 IMPL_LINK( MenuBarWindow, CloserHdl, PushButton*, EMPTYARG )
5142 if( ! pMenu )
5143 return 0;
5145 if( aCloser.GetCurItemId() == IID_DOCUMENTCLOSE )
5146 return ((MenuBar*)pMenu)->GetCloserHdl().Call( pMenu );
5147 std::map<USHORT,AddButtonEntry>::iterator it = m_aAddButtons.find( aCloser.GetCurItemId() );
5148 if( it != m_aAddButtons.end() )
5150 MenuBar::MenuBarButtonCallbackArg aArg;
5151 aArg.nId = it->first;
5152 aArg.bHighlight = (aCloser.GetHighlightItemId() == it->first);
5153 aArg.pMenuBar = dynamic_cast<MenuBar*>(pMenu);
5154 return it->second.m_aSelectLink.Call( &aArg );
5156 return 0;
5159 IMPL_LINK( MenuBarWindow, ToolboxEventHdl, VclWindowEvent*, pEvent )
5161 if( ! pMenu )
5162 return 0;
5164 MenuBar::MenuBarButtonCallbackArg aArg;
5165 aArg.nId = 0xffff;
5166 aArg.bHighlight = (pEvent->GetId() == VCLEVENT_TOOLBOX_HIGHLIGHT);
5167 aArg.pMenuBar = dynamic_cast<MenuBar*>(pMenu);
5168 if( pEvent->GetId() == VCLEVENT_TOOLBOX_HIGHLIGHT )
5169 aArg.nId = aCloser.GetHighlightItemId();
5170 else if( pEvent->GetId() == VCLEVENT_TOOLBOX_HIGHLIGHTOFF )
5172 USHORT nPos = static_cast< USHORT >(reinterpret_cast<sal_IntPtr>(pEvent->GetData()));
5173 aArg.nId = aCloser.GetItemId( nPos );
5175 std::map< USHORT, AddButtonEntry >::iterator it = m_aAddButtons.find( aArg.nId );
5176 if( it != m_aAddButtons.end() )
5178 it->second.m_aHighlightLink.Call( &aArg );
5180 return 0;
5183 IMPL_LINK( MenuBarWindow, ShowHideListener, VclWindowEvent*, pEvent )
5185 if( ! pMenu )
5186 return 0;
5188 if( pEvent->GetId() == VCLEVENT_WINDOW_SHOW )
5189 pMenu->ImplCallEventListeners( VCLEVENT_MENU_SHOW, ITEMPOS_INVALID );
5190 else if( pEvent->GetId() == VCLEVENT_WINDOW_HIDE )
5191 pMenu->ImplCallEventListeners( VCLEVENT_MENU_HIDE, ITEMPOS_INVALID );
5192 return 0;
5195 IMPL_LINK( MenuBarWindow, FloatHdl, PushButton*, EMPTYARG )
5197 return pMenu ? ((MenuBar*)pMenu)->GetFloatButtonClickHdl().Call( pMenu ) : 0;
5200 IMPL_LINK( MenuBarWindow, HideHdl, PushButton*, EMPTYARG )
5202 return pMenu ? ((MenuBar*)pMenu)->GetHideButtonClickHdl().Call( pMenu ) : 0;
5205 void MenuBarWindow::ImplCreatePopup( BOOL bPreSelectFirst )
5207 MenuItemData* pItemData = pMenu ? pMenu->GetItemList()->GetDataFromPos( nHighlightedItem ) : NULL;
5208 if ( pItemData )
5210 bIgnoreFirstMove = TRUE;
5211 if ( pActivePopup && ( pActivePopup != pItemData->pSubMenu ) )
5213 KillActivePopup();
5215 if ( pItemData->bEnabled && pItemData->pSubMenu && ( nHighlightedItem != ITEMPOS_INVALID ) && ( pItemData->pSubMenu != pActivePopup ) )
5217 pActivePopup = (PopupMenu*)pItemData->pSubMenu;
5218 long nX = 0;
5219 MenuItemData* pData = 0;
5220 for ( ULONG n = 0; n < nHighlightedItem; n++ )
5222 pData = pMenu->GetItemList()->GetDataFromPos( n );
5223 nX += pData->aSz.Width();
5225 pData = pMenu->pItemList->GetDataFromPos( nHighlightedItem );
5226 // Point MyPos = GetPosPixel();
5227 // Point aItemTopLeft( MyPos.X()+nX, MyPos.Y() );
5228 Point aItemTopLeft( nX, 0 );
5229 Point aItemBottomRight( aItemTopLeft );
5230 aItemBottomRight.X() += pData->aSz.Width();
5232 // Im Vollbild-Modus hat die MenuBar ggf. die Hoehe 0:
5233 // Nicht immer einfach die Window-Hoehe nehmen, weil ItemHeight < WindowHeight.
5234 if ( GetSizePixel().Height() )
5236 // #107747# give menuitems the height of the menubar
5237 aItemBottomRight.Y() += GetOutputSizePixel().Height()-1;
5240 // ImplExecute ist doch nicht modal...
5241 // #99071# do not grab the focus, otherwise it will be restored to the menubar
5242 // when the frame is reactivated later
5243 //GrabFocus();
5244 pActivePopup->ImplExecute( this, Rectangle( aItemTopLeft, aItemBottomRight ), FLOATWIN_POPUPMODE_DOWN, pMenu, bPreSelectFirst );
5245 if ( pActivePopup )
5247 // Hat kein Window, wenn vorher abgebrochen oder keine Eintraege
5248 if ( pActivePopup->ImplGetFloatingWindow() )
5249 pActivePopup->ImplGetFloatingWindow()->AddPopupModeWindow( this );
5250 else
5251 pActivePopup = NULL;
5258 void MenuBarWindow::KillActivePopup()
5260 if ( pActivePopup )
5262 if( pActivePopup->pWindow != NULL )
5263 if( ((FloatingWindow *) pActivePopup->pWindow)->IsInCleanUp() )
5264 return; // kill it later
5266 if ( pActivePopup->bInCallback )
5267 pActivePopup->bCanceled = TRUE;
5269 pActivePopup->bInCallback = TRUE;
5270 pActivePopup->Deactivate();
5271 pActivePopup->bInCallback = FALSE;
5272 // Abfrage auf pActivePopup, falls im Deactivate abgeschossen...
5273 if ( pActivePopup && pActivePopup->ImplGetWindow() )
5275 pActivePopup->ImplGetFloatingWindow()->StopExecute();
5276 pActivePopup->ImplGetFloatingWindow()->doShutdown();
5277 pActivePopup->pWindow->doLazyDelete();
5278 pActivePopup->pWindow = NULL;
5280 pActivePopup = 0;
5284 void MenuBarWindow::PopupClosed( Menu* pPopup )
5286 if ( pPopup == pActivePopup )
5288 KillActivePopup();
5289 ChangeHighlightItem( ITEMPOS_INVALID, FALSE, ImplGetFrameWindow()->ImplGetFrameData()->mbHasFocus, FALSE );
5293 void MenuBarWindow::MouseButtonDown( const MouseEvent& rMEvt )
5295 mbAutoPopup = TRUE;
5296 USHORT nEntry = ImplFindEntry( rMEvt.GetPosPixel() );
5297 if ( ( nEntry != ITEMPOS_INVALID ) && ( nEntry != nHighlightedItem ) )
5299 ChangeHighlightItem( nEntry, FALSE );
5301 else
5303 KillActivePopup();
5304 ChangeHighlightItem( ITEMPOS_INVALID, FALSE );
5308 void MenuBarWindow::MouseButtonUp( const MouseEvent& )
5312 void MenuBarWindow::MouseMove( const MouseEvent& rMEvt )
5314 // Im Move nur Highlighten, wenn schon eins gehighlightet.
5315 if ( rMEvt.IsSynthetic() || rMEvt.IsLeaveWindow() || rMEvt.IsEnterWindow() || ( nHighlightedItem == ITEMPOS_INVALID ) )
5316 return;
5318 if( bIgnoreFirstMove )
5320 bIgnoreFirstMove = FALSE;
5321 return;
5324 USHORT nEntry = ImplFindEntry( rMEvt.GetPosPixel() );
5325 if ( ( nEntry != ITEMPOS_INVALID )
5326 #ifdef OS2
5327 && ( ImplHilite(rMEvt) )
5328 #endif
5329 && ( nEntry != nHighlightedItem ) )
5330 ChangeHighlightItem( nEntry, FALSE );
5333 void MenuBarWindow::ChangeHighlightItem( USHORT n, BOOL bSelectEntry, BOOL bAllowRestoreFocus, BOOL bDefaultToDocument)
5335 if( ! pMenu )
5336 return;
5338 // #57934# ggf. das aktive Popup sofort schliessen, damit TH's Hintergrundsicherung funktioniert.
5339 MenuItemData* pNextData = pMenu->pItemList->GetDataFromPos( n );
5340 if ( pActivePopup && pActivePopup->ImplGetWindow() && ( !pNextData || ( pActivePopup != pNextData->pSubMenu ) ) )
5341 KillActivePopup(); // pActivePopup ggf. ohne pWin, wenn in Activate() Rescheduled wurde
5343 // Activate am MenuBar immer nur einmal pro Vorgang...
5344 BOOL bJustActivated = FALSE;
5345 if ( ( nHighlightedItem == ITEMPOS_INVALID ) && ( n != ITEMPOS_INVALID ) )
5347 ImplGetSVData()->maWinData.mbNoDeactivate = TRUE;
5348 if( !bStayActive )
5350 // #105406# avoid saving the focus when we already have the focus
5351 BOOL bNoSaveFocus = (this == ImplGetSVData()->maWinData.mpFocusWin );
5353 if( nSaveFocusId )
5355 if( !ImplGetSVData()->maWinData.mbNoSaveFocus )
5357 // we didn't clean up last time
5358 Window::EndSaveFocus( nSaveFocusId, FALSE ); // clean up
5359 nSaveFocusId = 0;
5360 if( !bNoSaveFocus )
5361 nSaveFocusId = Window::SaveFocus(); // only save focus when initially activated
5363 else {
5364 ; // do nothing: we 're activated again from taskpanelist, focus was already saved
5367 else
5369 if( !bNoSaveFocus )
5370 nSaveFocusId = Window::SaveFocus(); // only save focus when initially activated
5373 else
5374 bStayActive = FALSE;
5375 pMenu->bInCallback = TRUE; // hier schon setzen, falls Activate ueberladen
5376 pMenu->Activate();
5377 pMenu->bInCallback = FALSE;
5378 bJustActivated = TRUE;
5380 else if ( ( nHighlightedItem != ITEMPOS_INVALID ) && ( n == ITEMPOS_INVALID ) )
5382 pMenu->bInCallback = TRUE;
5383 pMenu->Deactivate();
5384 pMenu->bInCallback = FALSE;
5385 ImplGetSVData()->maWinData.mbNoDeactivate = FALSE;
5386 if( !ImplGetSVData()->maWinData.mbNoSaveFocus )
5388 ULONG nTempFocusId = nSaveFocusId;
5389 nSaveFocusId = 0;
5390 Window::EndSaveFocus( nTempFocusId, bAllowRestoreFocus );
5391 // #105406# restore focus to document if we could not save focus before
5392 if( bDefaultToDocument && !nTempFocusId && bAllowRestoreFocus )
5393 GrabFocusToDocument();
5397 if ( nHighlightedItem != ITEMPOS_INVALID )
5399 HighlightItem( nHighlightedItem, FALSE );
5400 pMenu->ImplCallEventListeners( VCLEVENT_MENU_DEHIGHLIGHT, nHighlightedItem );
5403 nHighlightedItem = (USHORT)n;
5404 DBG_ASSERT( ( nHighlightedItem == ITEMPOS_INVALID ) || pMenu->ImplIsVisible( nHighlightedItem ), "ChangeHighlightItem: Not visible!" );
5405 HighlightItem( nHighlightedItem, TRUE );
5406 pMenu->ImplCallHighlight( nHighlightedItem );
5408 if( mbAutoPopup )
5409 ImplCreatePopup( bSelectEntry );
5411 // #58935# #73659# Focus, wenn kein Popup drunter haengt...
5412 if ( bJustActivated && !pActivePopup )
5413 GrabFocus();
5416 void MenuBarWindow::HighlightItem( USHORT nPos, BOOL bHighlight )
5418 if( ! pMenu )
5419 return;
5421 long nX = 0;
5422 ULONG nCount = pMenu->pItemList->Count();
5423 for ( ULONG n = 0; n < nCount; n++ )
5425 MenuItemData* pData = pMenu->pItemList->GetDataFromPos( n );
5426 if ( n == nPos )
5428 if ( pData->eType != MENUITEM_SEPARATOR )
5430 // #107747# give menuitems the height of the menubar
5431 Rectangle aRect = Rectangle( Point( nX, 1 ), Size( pData->aSz.Width(), GetOutputSizePixel().Height()-2 ) );
5432 Push( PUSH_CLIPREGION );
5433 IntersectClipRegion( aRect );
5434 if ( bHighlight )
5436 if( IsNativeControlSupported( CTRL_MENUBAR, PART_MENU_ITEM ) &&
5437 IsNativeControlSupported( CTRL_MENUBAR, PART_ENTIRE_CONTROL ) )
5439 // draw background (transparency)
5440 ImplControlValue aControlValue;
5441 MenubarValue aMenubarValue;
5442 aMenubarValue.maTopDockingAreaHeight = ImplGetTopDockingAreaHeight( this );
5443 aControlValue.setOptionalVal( (void *)(&aMenubarValue) );
5445 Point tmp(0,0);
5446 Region aBgRegion( Rectangle( tmp, GetOutputSizePixel() ) );
5447 DrawNativeControl( CTRL_MENUBAR, PART_ENTIRE_CONTROL,
5448 aBgRegion,
5449 CTRL_STATE_ENABLED,
5450 aControlValue,
5451 OUString() );
5452 ImplAddNWFSeparator( this, aMenubarValue );
5454 // draw selected item
5455 DrawNativeControl( CTRL_MENUBAR, PART_MENU_ITEM,
5456 Region( aRect ),
5457 CTRL_STATE_ENABLED | CTRL_STATE_SELECTED,
5458 aControlValue,
5459 OUString() );
5461 else
5463 SetFillColor( GetSettings().GetStyleSettings().GetMenuHighlightColor() );
5464 SetLineColor();
5465 DrawRect( aRect );
5468 else
5470 if( IsNativeControlSupported( CTRL_MENUBAR, PART_ENTIRE_CONTROL) )
5472 ImplControlValue aControlValue;
5473 MenubarValue aMenubarValue;
5474 aMenubarValue.maTopDockingAreaHeight = ImplGetTopDockingAreaHeight( this );
5475 aControlValue.setOptionalVal( (void *)(&aMenubarValue) );
5477 // use full window size to get proper gradient
5478 // but clip accordingly
5479 Point aPt;
5480 Rectangle aCtrlRect( aPt, GetOutputSizePixel() );
5481 Region aCtrlRegion( aCtrlRect );
5483 DrawNativeControl( CTRL_MENUBAR, PART_ENTIRE_CONTROL, aCtrlRegion, CTRL_STATE_ENABLED, aControlValue, rtl::OUString() );
5484 ImplAddNWFSeparator( this, aMenubarValue );
5486 else
5487 Erase( aRect );
5489 Pop();
5490 pMenu->ImplPaint( this, 0, 0, pData, bHighlight );
5492 return;
5495 nX += pData->aSz.Width();
5499 Rectangle MenuBarWindow::ImplGetItemRect( USHORT nPos )
5501 Rectangle aRect;
5502 if( pMenu )
5504 long nX = 0;
5505 ULONG nCount = pMenu->pItemList->Count();
5506 for ( ULONG n = 0; n < nCount; n++ )
5508 MenuItemData* pData = pMenu->pItemList->GetDataFromPos( n );
5509 if ( n == nPos )
5511 if ( pData->eType != MENUITEM_SEPARATOR )
5512 // #107747# give menuitems the height of the menubar
5513 aRect = Rectangle( Point( nX, 1 ), Size( pData->aSz.Width(), GetOutputSizePixel().Height()-2 ) );
5514 break;
5517 nX += pData->aSz.Width();
5520 return aRect;
5523 void MenuBarWindow::KeyInput( const KeyEvent& rKEvent )
5525 if ( !ImplHandleKeyEvent( rKEvent ) )
5526 Window::KeyInput( rKEvent );
5529 BOOL MenuBarWindow::ImplHandleKeyEvent( const KeyEvent& rKEvent, BOOL bFromMenu )
5531 if( ! pMenu )
5532 return FALSE;
5534 if ( pMenu->bInCallback )
5535 return TRUE; // schlucken
5537 BOOL bDone = FALSE;
5538 USHORT nCode = rKEvent.GetKeyCode().GetCode();
5540 if( GetParent() )
5542 if( GetParent()->GetWindow( WINDOW_CLIENT )->IsSystemWindow() )
5544 SystemWindow *pSysWin = (SystemWindow*)GetParent()->GetWindow( WINDOW_CLIENT );
5545 if( pSysWin->GetTaskPaneList() )
5546 if( pSysWin->GetTaskPaneList()->HandleKeyEvent( rKEvent ) )
5547 return TRUE;
5551 if ( nCode == KEY_MENU && !rKEvent.GetKeyCode().IsShift() ) // only F10, not Shift-F10
5553 mbAutoPopup = ImplGetSVData()->maNWFData.mbOpenMenuOnF10;
5554 if ( nHighlightedItem == ITEMPOS_INVALID )
5556 ChangeHighlightItem( 0, FALSE );
5557 GrabFocus();
5559 else
5561 ChangeHighlightItem( ITEMPOS_INVALID, FALSE );
5562 nSaveFocusId = 0;
5564 bDone = TRUE;
5566 else if ( bFromMenu )
5568 if ( ( nCode == KEY_LEFT ) || ( nCode == KEY_RIGHT ) ||
5569 ( nCode == KEY_HOME ) || ( nCode == KEY_END ) )
5571 USHORT n = nHighlightedItem;
5572 if ( n == ITEMPOS_INVALID )
5574 if ( nCode == KEY_LEFT)
5575 n = 0;
5576 else
5577 n = pMenu->GetItemCount()-1;
5580 USHORT nLoop = n;
5582 if( nCode == KEY_HOME )
5583 { n = (USHORT)-1; nLoop = n+1; }
5584 if( nCode == KEY_END )
5585 { n = pMenu->GetItemCount(); nLoop = n-1; }
5589 if ( nCode == KEY_LEFT || nCode == KEY_END )
5591 if ( n )
5592 n--;
5593 else
5594 n = pMenu->GetItemCount()-1;
5596 if ( nCode == KEY_RIGHT || nCode == KEY_HOME )
5598 n++;
5599 if ( n >= pMenu->GetItemCount() )
5600 n = 0;
5603 MenuItemData* pData = (MenuItemData*)pMenu->GetItemList()->GetDataFromPos( n );
5604 if ( ( pData->eType != MENUITEM_SEPARATOR ) && pMenu->ImplIsVisible( n ) )
5606 ChangeHighlightItem( n, TRUE );
5607 break;
5609 } while ( n != nLoop );
5610 bDone = TRUE;
5612 else if ( nCode == KEY_RETURN )
5614 if( pActivePopup ) KillActivePopup();
5615 else
5616 if ( !mbAutoPopup )
5618 ImplCreatePopup( TRUE );
5619 mbAutoPopup = TRUE;
5621 bDone = TRUE;
5623 else if ( ( nCode == KEY_UP ) || ( nCode == KEY_DOWN ) )
5625 if ( !mbAutoPopup )
5627 ImplCreatePopup( TRUE );
5628 mbAutoPopup = TRUE;
5630 bDone = TRUE;
5632 else if ( nCode == KEY_ESCAPE || ( nCode == KEY_F6 && rKEvent.GetKeyCode().IsMod1() ) )
5634 if( pActivePopup )
5636 // bring focus to menu bar without any open popup
5637 mbAutoPopup = FALSE;
5638 USHORT n = nHighlightedItem;
5639 nHighlightedItem = ITEMPOS_INVALID;
5640 bStayActive = TRUE;
5641 ChangeHighlightItem( n, FALSE );
5642 bStayActive = FALSE;
5643 KillActivePopup();
5644 GrabFocus();
5646 else
5647 ChangeHighlightItem( ITEMPOS_INVALID, FALSE );
5649 if( nCode == KEY_F6 && rKEvent.GetKeyCode().IsMod1() )
5651 // put focus into document
5652 GrabFocusToDocument();
5655 bDone = TRUE;
5659 if ( !bDone && ( bFromMenu || rKEvent.GetKeyCode().IsMod2() ) )
5661 xub_Unicode nCharCode = rKEvent.GetCharCode();
5662 if ( nCharCode )
5664 USHORT nEntry, nDuplicates;
5665 MenuItemData* pData = pMenu->GetItemList()->SearchItem( nCharCode, rKEvent.GetKeyCode(), nEntry, nDuplicates, nHighlightedItem );
5666 if ( pData && (nEntry != ITEMPOS_INVALID) )
5668 mbAutoPopup = TRUE;
5669 ChangeHighlightItem( nEntry, TRUE );
5670 bDone = TRUE;
5672 else
5674 // Wegen Systemmenu und anderen System-HotKeys, nur
5675 // eigenstaendige Character-Kombinationen auswerten
5676 USHORT nKeyCode = rKEvent.GetKeyCode().GetCode();
5677 if ( ((nKeyCode >= KEY_A) && (nKeyCode <= KEY_Z)) )
5678 Sound::Beep();
5682 return bDone;
5685 void MenuBarWindow::Paint( const Rectangle& )
5687 if( ! pMenu )
5688 return;
5690 // no VCL paint if native menus
5691 if( pMenu->ImplGetSalMenu() && pMenu->ImplGetSalMenu()->VisibleMenuBar() )
5693 ImplGetFrame()->DrawMenuBar();
5694 return;
5697 if( IsNativeControlSupported( CTRL_MENUBAR, PART_ENTIRE_CONTROL) )
5699 Point aPt;
5700 Region aCtrlRegion( Rectangle( aPt, GetOutputSizePixel() ) );
5702 ImplControlValue aControlValue;
5703 MenubarValue aMenubarValue;
5704 aMenubarValue.maTopDockingAreaHeight = ImplGetTopDockingAreaHeight( this );
5705 aControlValue.setOptionalVal( (void *)(&aMenubarValue) );
5707 DrawNativeControl( CTRL_MENUBAR, PART_ENTIRE_CONTROL, aCtrlRegion, CTRL_STATE_ENABLED, aControlValue, rtl::OUString() );
5708 ImplAddNWFSeparator( this, aMenubarValue );
5710 SetFillColor( GetSettings().GetStyleSettings().GetMenuColor() );
5711 pMenu->ImplPaint( this, 0 );
5712 if ( nHighlightedItem != ITEMPOS_INVALID )
5713 HighlightItem( nHighlightedItem, TRUE );
5715 // in high contrast mode draw a separating line on the lower edge
5716 if( ! IsNativeControlSupported( CTRL_MENUBAR, PART_ENTIRE_CONTROL) &&
5717 GetSettings().GetStyleSettings().GetFaceColor().IsDark() )
5719 Push( PUSH_LINECOLOR | PUSH_MAPMODE );
5720 SetLineColor( Color( COL_WHITE ) );
5721 SetMapMode( MapMode( MAP_PIXEL ) );
5722 Size aSize = GetSizePixel();
5723 DrawLine( Point( 0, aSize.Height()-1 ), Point( aSize.Width()-1, aSize.Height()-1 ) );
5724 Pop();
5729 void MenuBarWindow::Resize()
5731 Size aOutSz = GetOutputSizePixel();
5732 long n = aOutSz.Height()-4;
5733 long nX = aOutSz.Width()-3;
5734 long nY = 2;
5736 if ( aCloser.IsVisible() )
5738 aCloser.Hide();
5739 aCloser.SetImages( n );
5740 Size aTbxSize( aCloser.CalcWindowSizePixel() );
5741 nX -= aTbxSize.Width();
5742 long nTbxY = (aOutSz.Height() - aTbxSize.Height())/2;
5743 aCloser.SetPosSizePixel( nX, nTbxY, aTbxSize.Width(), aTbxSize.Height() );
5744 nX -= 3;
5745 aCloser.Show();
5747 if ( aFloatBtn.IsVisible() )
5749 nX -= n;
5750 aFloatBtn.SetPosSizePixel( nX, nY, n, n );
5752 if ( aHideBtn.IsVisible() )
5754 nX -= n;
5755 aHideBtn.SetPosSizePixel( nX, nY, n, n );
5758 aFloatBtn.SetSymbol( SYMBOL_FLOAT );
5759 aHideBtn.SetSymbol( SYMBOL_HIDE );
5760 //aCloser.SetSymbol( SYMBOL_CLOSE ); //is a toolbox now
5762 Invalidate();
5765 USHORT MenuBarWindow::ImplFindEntry( const Point& rMousePos ) const
5767 if( pMenu )
5769 long nX = 0;
5770 USHORT nCount = (USHORT)pMenu->pItemList->Count();
5771 for ( USHORT n = 0; n < nCount; n++ )
5773 MenuItemData* pData = pMenu->pItemList->GetDataFromPos( n );
5774 if ( pMenu->ImplIsVisible( n ) )
5776 nX += pData->aSz.Width();
5777 if ( nX > rMousePos.X() )
5778 return (USHORT)n;
5782 return ITEMPOS_INVALID;
5785 void MenuBarWindow::RequestHelp( const HelpEvent& rHEvt )
5787 USHORT nId = nHighlightedItem;
5788 if ( rHEvt.GetMode() & (HELPMODE_CONTEXT | HELPMODE_EXTENDED) )
5789 ChangeHighlightItem( ITEMPOS_INVALID, TRUE );
5791 Rectangle aHighlightRect( ImplGetItemRect( nHighlightedItem ) );
5792 if( !ImplHandleHelpEvent( this, pMenu, nId, rHEvt, aHighlightRect ) )
5793 Window::RequestHelp( rHEvt );
5796 void MenuBarWindow::StateChanged( StateChangedType nType )
5798 Window::StateChanged( nType );
5800 if ( ( nType == STATE_CHANGE_CONTROLFOREGROUND ) ||
5801 ( nType == STATE_CHANGE_CONTROLBACKGROUND ) )
5803 ImplInitMenuWindow( this, FALSE, TRUE );
5804 Invalidate();
5806 else if( pMenu )
5807 pMenu->ImplKillLayoutData();
5811 void MenuBarWindow::ImplLayoutChanged()
5813 if( pMenu )
5815 ImplInitMenuWindow( this, TRUE, TRUE );
5816 // Falls sich der Font geaendert hat.
5817 long nHeight = pMenu->ImplCalcSize( this ).Height();
5819 // depending on the native implementation or the displayable flag
5820 // the menubar windows is supressed (ie, height=0)
5821 if( !((MenuBar*) pMenu)->IsDisplayable() ||
5822 ( pMenu->ImplGetSalMenu() && pMenu->ImplGetSalMenu()->VisibleMenuBar() ) )
5823 nHeight = 0;
5825 SetPosSizePixel( 0, 0, 0, nHeight, WINDOW_POSSIZE_HEIGHT );
5826 GetParent()->Resize();
5827 Invalidate();
5828 Resize();
5829 if( pMenu )
5830 pMenu->ImplKillLayoutData();
5834 void MenuBarWindow::ImplInitStyleSettings()
5836 if( IsNativeControlSupported( CTRL_MENUBAR, PART_MENU_ITEM ) &&
5837 IsNativeControlSupported( CTRL_MENUBAR, PART_ENTIRE_CONTROL ) )
5839 Color aHighlightTextColor = ImplGetSVData()->maNWFData.maMenuBarHighlightTextColor;
5840 if( aHighlightTextColor != Color( COL_TRANSPARENT ) )
5842 AllSettings aSettings( GetSettings() );
5843 StyleSettings aStyle( aSettings.GetStyleSettings() );
5844 aStyle.SetMenuHighlightTextColor( aHighlightTextColor );
5845 aSettings.SetStyleSettings( aStyle );
5846 OutputDevice::SetSettings( aSettings );
5851 void MenuBarWindow::DataChanged( const DataChangedEvent& rDCEvt )
5853 Window::DataChanged( rDCEvt );
5855 if ( (rDCEvt.GetType() == DATACHANGED_FONTS) ||
5856 (rDCEvt.GetType() == DATACHANGED_FONTSUBSTITUTION) ||
5857 ((rDCEvt.GetType() == DATACHANGED_SETTINGS) &&
5858 (rDCEvt.GetFlags() & SETTINGS_STYLE)) )
5860 ImplLayoutChanged();
5861 ImplInitStyleSettings();
5865 void MenuBarWindow::LoseFocus()
5867 if ( !HasChildPathFocus( TRUE ) )
5868 ChangeHighlightItem( ITEMPOS_INVALID, FALSE, FALSE );
5871 void MenuBarWindow::GetFocus()
5873 if ( nHighlightedItem == ITEMPOS_INVALID )
5875 mbAutoPopup = FALSE; // do not open menu when activated by focus handling like taskpane cycling
5876 ChangeHighlightItem( 0, FALSE );
5880 ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible > MenuBarWindow::CreateAccessible()
5882 ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible > xAcc;
5884 if ( pMenu )
5885 xAcc = pMenu->GetAccessible();
5887 return xAcc;
5890 USHORT MenuBarWindow::AddMenuBarButton( const Image& i_rImage, const Link& i_rLink, const String& i_rToolTip, USHORT i_nPos )
5892 // find first free button id
5893 USHORT nId = IID_DOCUMENTCLOSE;
5894 std::map< USHORT, AddButtonEntry >::const_iterator it;
5895 if( i_nPos > m_aAddButtons.size() )
5896 i_nPos = static_cast<USHORT>(m_aAddButtons.size());
5899 nId++;
5900 it = m_aAddButtons.find( nId );
5901 } while( it != m_aAddButtons.end() && nId < 128 );
5902 DBG_ASSERT( nId < 128, "too many addbuttons in menubar" );
5903 AddButtonEntry& rNewEntry = m_aAddButtons[nId];
5904 rNewEntry.m_nId = nId;
5905 rNewEntry.m_aSelectLink = i_rLink;
5906 aCloser.InsertItem( nId, i_rImage, 0, 0 );
5907 aCloser.calcMinSize();
5908 ShowButtons( aCloser.IsItemVisible( IID_DOCUMENTCLOSE ),
5909 aFloatBtn.IsVisible(),
5910 aHideBtn.IsVisible() );
5911 ImplLayoutChanged();
5913 if( pMenu->mpSalMenu )
5914 pMenu->mpSalMenu->AddMenuBarButton( SalMenuButtonItem( nId, i_rImage, i_rToolTip ) );
5916 return nId;
5919 void MenuBarWindow::SetMenuBarButtonHighlightHdl( USHORT nId, const Link& rLink )
5921 std::map< USHORT, AddButtonEntry >::iterator it = m_aAddButtons.find( nId );
5922 if( it != m_aAddButtons.end() )
5923 it->second.m_aHighlightLink = rLink;
5926 Rectangle MenuBarWindow::GetMenuBarButtonRectPixel( USHORT nId )
5928 Rectangle aRect;
5929 if( m_aAddButtons.find( nId ) != m_aAddButtons.end() )
5931 if( pMenu->mpSalMenu )
5933 aRect = pMenu->mpSalMenu->GetMenuBarButtonRectPixel( nId, ImplGetWindowImpl()->mpFrame );
5934 if( aRect == Rectangle( Point( -1, -1 ), Size( 1, 1 ) ) )
5936 // system menu button is somehwere but location cannot be determined
5937 return Rectangle();
5941 if( aRect.IsEmpty() )
5943 aRect = aCloser.GetItemRect( nId );
5944 Point aOffset = aCloser.OutputToScreenPixel( Point() );
5945 aRect.Move( aOffset.X(), aOffset.Y() );
5948 return aRect;
5951 void MenuBarWindow::RemoveMenuBarButton( USHORT nId )
5953 USHORT nPos = aCloser.GetItemPos( nId );
5954 aCloser.RemoveItem( nPos );
5955 m_aAddButtons.erase( nId );
5956 aCloser.calcMinSize();
5957 ImplLayoutChanged();
5959 if( pMenu->mpSalMenu )
5960 pMenu->mpSalMenu->RemoveMenuBarButton( nId );
5963 bool MenuBarWindow::HandleMenuButtonEvent( USHORT i_nButtonId )
5965 std::map< USHORT, AddButtonEntry >::iterator it = m_aAddButtons.find( i_nButtonId );
5966 if( it != m_aAddButtons.end() )
5968 MenuBar::MenuBarButtonCallbackArg aArg;
5969 aArg.nId = it->first;
5970 aArg.bHighlight = true;
5971 aArg.pMenuBar = dynamic_cast<MenuBar*>(pMenu);
5972 return it->second.m_aSelectLink.Call( &aArg );
5974 return FALSE;