1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/mac/carbon/menu.cpp
3 // Purpose: wxMenu, wxMenuBar, wxMenuItem
4 // Author: Stefan Csomor
8 // Copyright: (c) Stefan Csomor
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
12 // ============================================================================
13 // headers & declarations
14 // ============================================================================
19 #include "wx/wxprec.h"
28 #include "wx/menuitem.h"
31 #include "wx/mac/uma.h"
33 // other standard headers
34 // ----------------------
37 IMPLEMENT_DYNAMIC_CLASS(wxMenu
, wxEvtHandler
)
38 IMPLEMENT_DYNAMIC_CLASS(wxMenuBar
, wxEvtHandler
)
40 // the (popup) menu title has this special id
41 static const int idMenuTitle
= -3;
43 static const short kwxMacAppleMenuId
= 1 ;
46 // Find an item given the Macintosh Menu Reference
48 WX_DECLARE_HASH_MAP(MenuRef
, wxMenu
*, wxPointerHash
, wxPointerEqual
, MacMenuMap
);
50 static MacMenuMap wxWinMacMenuList
;
52 wxMenu
*wxFindMenuFromMacMenu(MenuRef inMenuRef
)
54 MacMenuMap::iterator node
= wxWinMacMenuList
.find(inMenuRef
);
56 return (node
== wxWinMacMenuList
.end()) ? NULL
: node
->second
;
59 void wxAssociateMenuWithMacMenu(MenuRef inMenuRef
, wxMenu
*menu
) ;
60 void wxAssociateMenuWithMacMenu(MenuRef inMenuRef
, wxMenu
*menu
)
62 // adding NULL MenuRef is (first) surely a result of an error and
63 // (secondly) breaks menu command processing
64 wxCHECK_RET( inMenuRef
!= (MenuRef
) NULL
, wxT("attempt to add a NULL MenuRef to menu list") );
66 wxWinMacMenuList
[inMenuRef
] = menu
;
69 void wxRemoveMacMenuAssociation(wxMenu
*menu
) ;
70 void wxRemoveMacMenuAssociation(wxMenu
*menu
)
72 // iterate over all the elements in the class
73 MacMenuMap::iterator it
;
74 for ( it
= wxWinMacMenuList
.begin(); it
!= wxWinMacMenuList
.end(); ++it
)
76 if ( it
->second
== menu
)
78 wxWinMacMenuList
.erase(it
);
84 void wxInsertMenuItemsInMenu(wxMenu
* menu
, MenuRef wm
, MenuItemIndex insertAfter
)
86 wxMenuItemList::compatibility_iterator node
;
88 wxMenu
*subMenu
= NULL
;
89 bool newItems
= false;
91 for (node
= menu
->GetMenuItems().GetFirst(); node
; node
= node
->GetNext())
93 item
= (wxMenuItem
*)node
->GetData();
94 subMenu
= item
->GetSubMenu() ;
97 wxInsertMenuItemsInMenu(subMenu
, (MenuRef
)subMenu
->GetHMenu(), 0);
99 if ( item
->IsSeparator() )
102 InsertMenuItemTextWithCFString( wm
,
103 CFSTR(""), insertAfter
, kMenuItemAttrSeparator
, 0);
110 entry
= wxAcceleratorEntry::Create( item
->GetItemLabel() ) ;
112 MenuItemIndex winListPos
= (MenuItemIndex
)-1;
113 OSStatus err
= GetIndMenuItemWithCommandID(wm
,
114 wxIdToMacCommand ( item
->GetId() ), 1, NULL
, &winListPos
);
116 if ( wm
&& err
== menuItemNotFoundErr
)
118 // NB: the only way to determine whether or not we should add
119 // a separator is to know if we've added menu items to the menu
120 // before the separator.
122 UMAInsertMenuItem(wm
, wxStripMenuCodes(item
->GetItemLabel()) , wxFont::GetDefaultEncoding(), insertAfter
, entry
);
123 SetMenuItemCommandID( wm
, insertAfter
+1 , wxIdToMacCommand ( item
->GetId() ) ) ;
124 SetMenuItemRefCon( wm
, insertAfter
+1 , (URefCon
) item
) ;
132 // ============================================================================
134 // ============================================================================
135 static void wxMenubarUnsetInvokingWindow( wxMenu
*menu
) ;
136 static void wxMenubarSetInvokingWindow( wxMenu
*menu
, wxWindow
*win
);
140 // Construct a menu with optional title (then use append)
143 short wxMenu::s_macNextMenuId
= 3 ;
145 short wxMenu::s_macNextMenuId
= 2 ;
150 _wxMenuAt(const wxMenuList
&menuList
, size_t pos
)
152 wxMenuList::compatibility_iterator menuIter
= menuList
.GetFirst();
155 menuIter
= menuIter
->GetNext();
157 return menuIter
->GetData() ;
163 m_startRadioGroup
= -1;
166 m_macMenuId
= s_macNextMenuId
++;
167 m_hMenu
= UMANewMenu(m_macMenuId
, m_title
, wxFont::GetDefaultEncoding() );
171 wxLogLastError(wxT("UMANewMenu failed"));
174 wxAssociateMenuWithMacMenu( (MenuRef
)m_hMenu
, this ) ;
176 // if we have a title, insert it in the beginning of the menu
177 if ( !m_title
.empty() )
179 Append(idMenuTitle
, m_title
) ;
186 wxRemoveMacMenuAssociation( this ) ;
187 if (MAC_WXHMENU(m_hMenu
))
188 ::DisposeMenu(MAC_WXHMENU(m_hMenu
));
193 // not available on the mac platform
196 void wxMenu::Attach(wxMenuBarBase
*menubar
)
198 wxMenuBase::Attach(menubar
);
203 // function appends a new item or submenu to the menu
204 // append a new item or submenu to the menu
205 bool wxMenu::DoInsertOrAppend(wxMenuItem
*pItem
, size_t pos
)
207 wxASSERT_MSG( pItem
!= NULL
, wxT("can't append NULL item to the menu") );
209 if ( pItem
->IsSeparator() )
211 if ( pos
== (size_t)-1 )
212 AppendMenuItemTextWithCFString( MAC_WXHMENU(m_hMenu
),
213 CFSTR(""), kMenuItemAttrSeparator
, 0,NULL
);
215 InsertMenuItemTextWithCFString( MAC_WXHMENU(m_hMenu
),
216 CFSTR(""), pos
, kMenuItemAttrSeparator
, 0);
220 wxMenu
*pSubMenu
= pItem
->GetSubMenu() ;
221 if ( pSubMenu
!= NULL
)
223 wxASSERT_MSG( pSubMenu
->m_hMenu
!= NULL
, wxT("invalid submenu added"));
224 pSubMenu
->m_menuParent
= this ;
226 if (wxMenuBar::MacGetInstalledMenuBar() == GetMenuBar())
227 pSubMenu
->MacBeforeDisplay( true ) ;
229 if ( pos
== (size_t)-1 )
230 UMAAppendSubMenuItem(MAC_WXHMENU(m_hMenu
), wxStripMenuCodes(pItem
->GetItemLabel()), wxFont::GetDefaultEncoding(), pSubMenu
->m_macMenuId
);
232 UMAInsertSubMenuItem(MAC_WXHMENU(m_hMenu
), wxStripMenuCodes(pItem
->GetItemLabel()), wxFont::GetDefaultEncoding(), pos
, pSubMenu
->m_macMenuId
);
234 pItem
->UpdateItemBitmap() ;
235 pItem
->UpdateItemStatus() ;
239 if ( pos
== (size_t)-1 )
241 UMAAppendMenuItem(MAC_WXHMENU(m_hMenu
), wxT("a") , wxFont::GetDefaultEncoding() );
242 pos
= CountMenuItems(MAC_WXHMENU(m_hMenu
)) ;
246 // MacOS counts menu items from 1 and inserts after, therefore having the
247 // same effect as wx 0 based and inserting before, we must correct pos
248 // after however for updates to be correct
249 UMAInsertMenuItem(MAC_WXHMENU(m_hMenu
), wxT("a"), wxFont::GetDefaultEncoding(), pos
);
253 SetMenuItemCommandID( MAC_WXHMENU(m_hMenu
) , pos
, wxIdToMacCommand ( pItem
->GetId() ) ) ;
254 SetMenuItemRefCon( MAC_WXHMENU(m_hMenu
) , pos
, (URefCon
) pItem
) ;
255 pItem
->UpdateItemText() ;
256 pItem
->UpdateItemBitmap() ;
257 pItem
->UpdateItemStatus() ;
259 if ( pItem
->GetId() == idMenuTitle
)
260 UMAEnableMenuItem(MAC_WXHMENU(m_hMenu
) , pos
, false ) ;
264 // if we're already attached to the menubar, we must update it
265 if ( IsAttached() && GetMenuBar()->IsAttached() )
266 GetMenuBar()->Refresh();
271 void wxMenu::EndRadioGroup()
273 // we're not inside a radio group any longer
274 m_startRadioGroup
= -1;
277 wxMenuItem
* wxMenu::DoAppend(wxMenuItem
*item
)
279 wxCHECK_MSG( item
, NULL
, _T("NULL item in wxMenu::DoAppend") );
283 if ( item
->GetKind() == wxITEM_RADIO
)
285 int count
= GetMenuItemCount();
287 if ( m_startRadioGroup
== -1 )
289 // start a new radio group
290 m_startRadioGroup
= count
;
292 // for now it has just one element
293 item
->SetAsRadioGroupStart();
294 item
->SetRadioGroupEnd(m_startRadioGroup
);
296 // ensure that we have a checked item in the radio group
299 else // extend the current radio group
301 // we need to update its end item
302 item
->SetRadioGroupStart(m_startRadioGroup
);
303 wxMenuItemList::compatibility_iterator node
= GetMenuItems().Item(m_startRadioGroup
);
307 node
->GetData()->SetRadioGroupEnd(count
);
311 wxFAIL_MSG( _T("where is the radio group start item?") );
315 else // not a radio item
320 if ( !wxMenuBase::DoAppend(item
) || !DoInsertOrAppend(item
) )
324 // check the item initially
330 wxMenuItem
* wxMenu::DoInsert(size_t pos
, wxMenuItem
*item
)
332 if (wxMenuBase::DoInsert(pos
, item
) && DoInsertOrAppend(item
, pos
))
338 wxMenuItem
*wxMenu::DoRemove(wxMenuItem
*item
)
340 // we need to find the items position in the child list
342 wxMenuItemList::compatibility_iterator node
= GetMenuItems().GetFirst();
344 for ( pos
= 0; node
; pos
++ )
346 if ( node
->GetData() == item
)
349 node
= node
->GetNext();
352 // DoRemove() (unlike Remove) can only be called for existing item!
353 wxCHECK_MSG( node
, NULL
, wxT("bug in wxMenu::Remove logic") );
355 ::DeleteMenuItem(MAC_WXHMENU(m_hMenu
) , pos
+ 1);
357 if ( IsAttached() && GetMenuBar()->IsAttached() )
358 // otherwise, the change won't be visible
359 GetMenuBar()->Refresh();
361 // and from internal data structures
362 return wxMenuBase::DoRemove(item
);
365 void wxMenu::SetTitle(const wxString
& label
)
368 UMASetMenuTitle(MAC_WXHMENU(m_hMenu
) , label
, wxFont::GetDefaultEncoding() ) ;
371 bool wxMenu::ProcessCommand(wxCommandEvent
& event
)
373 bool processed
= false;
375 // Try the menu's event handler
376 if ( /* !processed && */ GetEventHandler())
377 processed
= GetEventHandler()->ProcessEvent(event
);
379 // Try the window the menu was popped up from
380 // (and up through the hierarchy)
381 wxWindow
*win
= GetInvokingWindow();
382 if ( !processed
&& win
)
383 processed
= win
->GetEventHandler()->ProcessEvent(event
);
388 // ---------------------------------------------------------------------------
390 // ---------------------------------------------------------------------------
392 wxWindow
*wxMenu::GetWindow() const
394 if ( m_invokingWindow
!= NULL
)
395 return m_invokingWindow
;
396 else if ( GetMenuBar() != NULL
)
397 return (wxWindow
*) GetMenuBar()->GetFrame();
402 // helper functions returning the mac menu position for a certain item, note that this is
403 // mac-wise 1 - based, i.e. the first item has index 1 whereas on MSWin it has pos 0
405 int wxMenu::MacGetIndexFromId( int id
)
408 wxMenuItemList::compatibility_iterator node
= GetMenuItems().GetFirst();
409 for ( pos
= 0; node
; pos
++ )
411 if ( node
->GetData()->GetId() == id
)
414 node
= node
->GetNext();
423 int wxMenu::MacGetIndexFromItem( wxMenuItem
*pItem
)
426 wxMenuItemList::compatibility_iterator node
= GetMenuItems().GetFirst();
427 for ( pos
= 0; node
; pos
++ )
429 if ( node
->GetData() == pItem
)
432 node
= node
->GetNext();
441 void wxMenu::MacEnableMenu( bool bDoEnable
)
443 UMAEnableMenuItem(MAC_WXHMENU(m_hMenu
) , 0 , bDoEnable
) ;
448 // MacOS needs to know about submenus somewhere within this menu
449 // before it can be displayed, also hide special menu items
450 // like preferences that are handled by the OS
451 void wxMenu::MacBeforeDisplay( bool isSubMenu
)
453 wxMenuItem
* previousItem
= NULL
;
455 wxMenuItemList::compatibility_iterator node
;
458 for (pos
= 0, node
= GetMenuItems().GetFirst(); node
; node
= node
->GetNext(), pos
++)
460 item
= (wxMenuItem
*)node
->GetData();
461 wxMenu
* subMenu
= item
->GetSubMenu() ;
464 subMenu
->MacBeforeDisplay( true ) ;
469 // what we do here is to hide the special items which are
470 // shown in the application menu anyhow -- it doesn't make
471 // sense to show them in their normal place as well
472 if ( item
->GetId() == wxApp::s_macAboutMenuItemId
||
473 ( UMAGetSystemVersion() >= 0x1000 && (
474 item
->GetId() == wxApp::s_macPreferencesMenuItemId
||
475 item
->GetId() == wxApp::s_macExitMenuItemId
) ) )
478 ChangeMenuItemAttributes( MAC_WXHMENU( GetHMenu() ),
479 pos
+ 1, kMenuItemAttrHidden
, 0 );
481 // also check for a separator which was used just to
482 // separate this item from the others, so don't leave
483 // separator at the menu start or end nor 2 consecutive
485 wxMenuItemList::compatibility_iterator nextNode
= node
->GetNext();
486 wxMenuItem
*next
= nextNode
? nextNode
->GetData() : NULL
;
489 if ( !previousItem
&& next
&& next
->IsSeparator() )
491 // next (i.e. second as we must be first) item is
492 // the separator to hide
493 wxASSERT_MSG( pos
== 0, _T("should be the menu start") );
496 else if ( GetMenuItems().GetCount() == pos
+ 1 &&
497 previousItem
!= NULL
&&
498 previousItem
->IsSeparator() )
500 // prev item is a trailing separator we want to hide
503 else if ( previousItem
&& previousItem
->IsSeparator() &&
504 next
&& next
->IsSeparator() )
506 // two consecutive separators, this is one too many
509 else // no separators to hide
516 // hide the separator as well
517 ChangeMenuItemAttributes( MAC_WXHMENU( GetHMenu() ),
523 #endif // TARGET_CARBON
526 previousItem
= item
;
530 ::InsertMenu(MAC_WXHMENU( GetHMenu()), -1);
533 // undo all changes from the MacBeforeDisplay call
534 void wxMenu::MacAfterDisplay( bool isSubMenu
)
537 ::DeleteMenu(MacGetMenuId());
539 wxMenuItemList::compatibility_iterator node
;
542 for (node
= GetMenuItems().GetFirst(); node
; node
= node
->GetNext())
544 item
= (wxMenuItem
*)node
->GetData();
545 wxMenu
* subMenu
= item
->GetSubMenu() ;
548 subMenu
->MacAfterDisplay( true ) ;
552 // no need to undo hidings
561 Mac Implementation note :
563 The Mac has only one global menubar, so we attempt to install the currently
564 active menubar from a frame, we currently don't take into account mdi-frames
565 which would ask for menu-merging
567 Secondly there is no mac api for changing a menubar that is not the current
568 menubar, so we have to wait for preparing the actual menubar until the
569 wxMenubar is to be used
571 We can in subsequent versions use MacInstallMenuBar to provide some sort of
572 auto-merge for MDI in case this will be necessary
576 wxMenuBar
* wxMenuBar::s_macInstalledMenuBar
= NULL
;
577 wxMenuBar
* wxMenuBar::s_macCommonMenuBar
= NULL
;
578 bool wxMenuBar::s_macAutoWindowMenu
= true ;
579 WXHMENU
wxMenuBar::s_macWindowMenuHandle
= NULL
;
581 void wxMenuBar::Init()
583 m_eventHandler
= this;
584 m_menuBarFrame
= NULL
;
585 m_invokingWindow
= (wxWindow
*) NULL
;
588 wxMenuBar::wxMenuBar()
593 wxMenuBar::wxMenuBar( long WXUNUSED(style
) )
598 wxMenuBar::wxMenuBar(size_t count
, wxMenu
*menus
[], const wxString titles
[], long WXUNUSED(style
))
602 m_titles
.Alloc(count
);
604 for ( size_t i
= 0; i
< count
; i
++ )
606 m_menus
.Append(menus
[i
]);
607 m_titles
.Add(titles
[i
]);
609 menus
[i
]->Attach(this);
613 wxMenuBar::~wxMenuBar()
615 if (s_macCommonMenuBar
== this)
616 s_macCommonMenuBar
= NULL
;
618 if (s_macInstalledMenuBar
== this)
621 s_macInstalledMenuBar
= NULL
;
625 void wxMenuBar::Refresh(bool WXUNUSED(eraseBackground
), const wxRect
*WXUNUSED(rect
))
627 wxCHECK_RET( IsAttached(), wxT("can't refresh unatteched menubar") );
632 void wxMenuBar::MacInstallMenuBar()
634 if ( s_macInstalledMenuBar
== this )
637 MenuBarHandle menubar
= NULL
;
639 #if TARGET_API_MAC_OSX
640 menubar
= NewHandleClear( 6 /* sizeof( MenuBarHeader ) */ ) ;
642 menubar
= NewHandleClear( 12 ) ;
643 (*menubar
)[3] = 0x0a ;
646 ::SetMenuBar( menubar
) ;
647 DisposeMenuBar( menubar
) ;
648 MenuHandle appleMenu
= NULL
;
650 verify_noerr( CreateNewMenu( kwxMacAppleMenuId
, 0 , &appleMenu
) ) ;
651 verify_noerr( SetMenuTitleWithCFString( appleMenu
, CFSTR( "\x14" ) ) );
653 // Add About/Preferences separator only on OS X
654 // KH/RN: Separator is always present on 10.3 but not on 10.2
655 // However, the change from 10.2 to 10.3 suggests it is preferred
656 #if TARGET_API_MAC_OSX
657 InsertMenuItemTextWithCFString( appleMenu
,
658 CFSTR(""), 0, kMenuItemAttrSeparator
, 0);
660 InsertMenuItemTextWithCFString( appleMenu
,
661 CFSTR("About..."), 0, 0, 0);
662 MacInsertMenu( appleMenu
, 0 ) ;
664 // if we have a mac help menu, clean it up before adding new items
665 MenuHandle helpMenuHandle
;
666 MenuItemIndex firstUserHelpMenuItem
;
668 if ( UMAGetHelpMenuDontCreate( &helpMenuHandle
, &firstUserHelpMenuItem
) == noErr
)
670 for ( int i
= CountMenuItems( helpMenuHandle
) ; i
>= firstUserHelpMenuItem
; --i
)
671 DeleteMenuItem( helpMenuHandle
, i
) ;
675 helpMenuHandle
= NULL
;
679 if ( UMAGetSystemVersion() >= 0x1000 && wxApp::s_macPreferencesMenuItemId
)
681 wxMenuItem
*item
= FindItem( wxApp::s_macPreferencesMenuItemId
, NULL
) ;
682 if ( item
== NULL
|| !(item
->IsEnabled()) )
683 DisableMenuCommand( NULL
, kHICommandPreferences
) ;
685 EnableMenuCommand( NULL
, kHICommandPreferences
) ;
688 // Unlike preferences which may or may not exist, the Quit item should be always
689 // enabled unless it is added by the application and then disabled, otherwise
690 // a program would be required to add an item with wxID_EXIT in order to get the
691 // Quit menu item to be enabled, which seems a bit burdensome.
692 if ( UMAGetSystemVersion() >= 0x1000 && wxApp::s_macExitMenuItemId
)
694 wxMenuItem
*item
= FindItem( wxApp::s_macExitMenuItemId
, NULL
) ;
695 if ( item
!= NULL
&& !(item
->IsEnabled()) )
696 DisableMenuCommand( NULL
, kHICommandQuit
) ;
698 EnableMenuCommand( NULL
, kHICommandQuit
) ;
702 wxString strippedHelpMenuTitle
= wxStripMenuCodes( wxApp::s_macHelpMenuTitleName
) ;
703 wxString strippedTranslatedHelpMenuTitle
= wxStripMenuCodes( wxString( _("&Help") ) ) ;
704 wxMenuList::compatibility_iterator menuIter
= m_menus
.GetFirst();
705 for (size_t i
= 0; i
< m_menus
.GetCount(); i
++, menuIter
= menuIter
->GetNext())
707 wxMenuItemList::compatibility_iterator node
;
709 wxMenu
* menu
= menuIter
->GetData() , *subMenu
= NULL
;
710 wxString strippedMenuTitle
= wxStripMenuCodes(m_titles
[i
]);
712 if ( strippedMenuTitle
== wxT("?") || strippedMenuTitle
== strippedHelpMenuTitle
|| strippedMenuTitle
== strippedTranslatedHelpMenuTitle
)
714 for (node
= menu
->GetMenuItems().GetFirst(); node
; node
= node
->GetNext())
716 item
= (wxMenuItem
*)node
->GetData();
717 subMenu
= item
->GetSubMenu() ;
720 // we don't support hierarchical menus in the help menu yet
724 if ( item
->GetId() != wxApp::s_macAboutMenuItemId
)
726 // we have found a user help menu and an item other than the about item,
727 // so we can create the mac help menu now, if we haven't created it yet
728 if ( helpMenuHandle
== NULL
)
730 if ( UMAGetHelpMenu( &helpMenuHandle
, &firstUserHelpMenuItem
) != noErr
)
732 helpMenuHandle
= NULL
;
738 if ( item
->IsSeparator() )
740 if ( helpMenuHandle
)
741 AppendMenuItemTextWithCFString( helpMenuHandle
,
742 CFSTR(""), kMenuItemAttrSeparator
, 0,NULL
);
747 entry
= wxAcceleratorEntry::Create( item
->GetItemLabel() ) ;
749 if ( item
->GetId() == wxApp::s_macAboutMenuItemId
)
751 // this will be taken care of below
755 if ( helpMenuHandle
)
757 UMAAppendMenuItem(helpMenuHandle
, wxStripMenuCodes(item
->GetItemLabel()) , wxFont::GetDefaultEncoding(), entry
);
758 SetMenuItemCommandID( helpMenuHandle
, CountMenuItems(helpMenuHandle
) , wxIdToMacCommand ( item
->GetId() ) ) ;
759 SetMenuItemRefCon( helpMenuHandle
, CountMenuItems(helpMenuHandle
) , (URefCon
) item
) ;
769 else if ( ( m_titles
[i
] == wxT("Window") || m_titles
[i
] == wxT("&Window") )
770 && GetAutoWindowMenu() )
772 if ( MacGetWindowMenuHMenu() == NULL
)
774 CreateStandardWindowMenu( 0 , (MenuHandle
*) &s_macWindowMenuHandle
) ;
777 MenuRef wm
= (MenuRef
)MacGetWindowMenuHMenu();
781 // get the insertion point in the standard menu
782 MenuItemIndex winListStart
;
783 GetIndMenuItemWithCommandID(wm
,
784 kHICommandWindowListSeparator
, 1, NULL
, &winListStart
);
786 // add a separator so that the standard items and the custom items
787 // aren't mixed together, but only if this is the first run
788 OSStatus err
= GetIndMenuItemWithCommandID(wm
,
789 'WXWM', 1, NULL
, NULL
);
791 if ( err
== menuItemNotFoundErr
)
793 InsertMenuItemTextWithCFString( wm
,
794 CFSTR(""), winListStart
-1, kMenuItemAttrSeparator
, 'WXWM');
797 wxInsertMenuItemsInMenu(menu
, wm
, winListStart
);
801 UMASetMenuTitle( MAC_WXHMENU(menu
->GetHMenu()) , m_titles
[i
], m_font
.GetEncoding() ) ;
802 menu
->MacBeforeDisplay(false) ;
804 ::InsertMenu(MAC_WXHMENU(_wxMenuAt(m_menus
, i
)->GetHMenu()), 0);
808 // take care of the about menu item wherever it is
811 wxMenuItem
*aboutMenuItem
= FindItem(wxApp::s_macAboutMenuItemId
, &aboutMenu
) ;
815 entry
= wxAcceleratorEntry::Create( aboutMenuItem
->GetItemLabel() ) ;
816 UMASetMenuItemText( GetMenuHandle( kwxMacAppleMenuId
) , 1 , wxStripMenuCodes ( aboutMenuItem
->GetItemLabel() ) , wxFont::GetDefaultEncoding() );
817 UMAEnableMenuItem( GetMenuHandle( kwxMacAppleMenuId
) , 1 , true );
818 SetMenuItemCommandID( GetMenuHandle( kwxMacAppleMenuId
) , 1 , kHICommandAbout
) ;
819 SetMenuItemRefCon(GetMenuHandle( kwxMacAppleMenuId
) , 1 , (URefCon
)aboutMenuItem
) ;
820 UMASetMenuItemShortcut( GetMenuHandle( kwxMacAppleMenuId
) , 1 , entry
) ;
824 if ( GetAutoWindowMenu() )
826 if ( MacGetWindowMenuHMenu() == NULL
)
827 CreateStandardWindowMenu( 0 , (MenuHandle
*) &s_macWindowMenuHandle
) ;
829 InsertMenu( (MenuHandle
) MacGetWindowMenuHMenu() , 0 ) ;
833 s_macInstalledMenuBar
= this;
836 void wxMenuBar::EnableTop(size_t pos
, bool enable
)
838 wxCHECK_RET( IsAttached(), wxT("doesn't work with unattached menubars") );
840 _wxMenuAt(m_menus
, pos
)->MacEnableMenu( enable
) ;
844 bool wxMenuBar::Enable(bool enable
)
846 wxCHECK_MSG( IsAttached(), false, wxT("doesn't work with unattached menubars") );
849 for (i
= 0; i
< GetMenuCount(); i
++)
850 EnableTop(i
, enable
);
855 void wxMenuBar::SetMenuLabel(size_t pos
, const wxString
& label
)
857 wxCHECK_RET( pos
< GetMenuCount(), wxT("invalid menu index") );
859 m_titles
[pos
] = label
;
864 _wxMenuAt(m_menus
, pos
)->SetTitle( label
) ;
866 if (wxMenuBar::s_macInstalledMenuBar
== this) // are we currently installed ?
868 ::SetMenuBar( GetMenuBar() ) ;
873 wxString
wxMenuBar::GetMenuLabel(size_t pos
) const
875 wxCHECK_MSG( pos
< GetMenuCount(), wxEmptyString
,
876 wxT("invalid menu index in wxMenuBar::GetMenuLabel") );
878 return m_titles
[pos
];
881 int wxMenuBar::FindMenu(const wxString
& title
)
883 wxString menuTitle
= wxStripMenuCodes(title
);
885 size_t count
= GetMenuCount();
886 for ( size_t i
= 0; i
< count
; i
++ )
888 wxString title
= wxStripMenuCodes(m_titles
[i
]);
889 if ( menuTitle
== title
)
896 // ---------------------------------------------------------------------------
897 // wxMenuBar construction
898 // ---------------------------------------------------------------------------
900 wxMenu
*wxMenuBar::Replace(size_t pos
, wxMenu
*menu
, const wxString
& title
)
902 wxMenu
*menuOld
= wxMenuBarBase::Replace(pos
, menu
, title
);
906 m_titles
[pos
] = title
;
910 if (s_macInstalledMenuBar
== this)
912 menuOld
->MacAfterDisplay( false ) ;
913 ::DeleteMenu( menuOld
->MacGetMenuId() /* m_menus[pos]->MacGetMenuId() */ ) ;
915 menu
->MacBeforeDisplay( false ) ;
916 UMASetMenuTitle( MAC_WXHMENU(menu
->GetHMenu()) , title
, m_font
.GetEncoding() ) ;
917 if ( pos
== m_menus
.GetCount() - 1)
918 ::InsertMenu( MAC_WXHMENU(menu
->GetHMenu()) , 0 ) ;
920 ::InsertMenu( MAC_WXHMENU(menu
->GetHMenu()) , _wxMenuAt(m_menus
, pos
+ 1)->MacGetMenuId() ) ;
926 if (m_invokingWindow
)
927 wxMenubarSetInvokingWindow( menu
, m_invokingWindow
);
932 bool wxMenuBar::Insert(size_t pos
, wxMenu
*menu
, const wxString
& title
)
934 if ( !wxMenuBarBase::Insert(pos
, menu
, title
) )
937 m_titles
.Insert(title
, pos
);
939 UMASetMenuTitle( MAC_WXHMENU(menu
->GetHMenu()) , title
, m_font
.GetEncoding() ) ;
941 if ( IsAttached() && s_macInstalledMenuBar
== this )
943 if (s_macInstalledMenuBar
== this)
945 menu
->MacBeforeDisplay( false ) ;
947 if ( pos
== (size_t) -1 || pos
+ 1 == m_menus
.GetCount() )
948 ::InsertMenu( MAC_WXHMENU(menu
->GetHMenu()) , 0 ) ;
950 ::InsertMenu( MAC_WXHMENU(menu
->GetHMenu()) , _wxMenuAt(m_menus
, pos
+1)->MacGetMenuId() ) ;
956 if (m_invokingWindow
)
957 wxMenubarSetInvokingWindow( menu
, m_invokingWindow
);
962 wxMenu
*wxMenuBar::Remove(size_t pos
)
964 wxMenu
*menu
= wxMenuBarBase::Remove(pos
);
970 if (s_macInstalledMenuBar
== this)
971 ::DeleteMenu( menu
->MacGetMenuId() /* m_menus[pos]->MacGetMenuId() */ ) ;
976 m_titles
.RemoveAt(pos
);
981 bool wxMenuBar::Append(wxMenu
*menu
, const wxString
& title
)
983 WXHMENU submenu
= menu
? menu
->GetHMenu() : 0;
984 wxCHECK_MSG( submenu
, false, wxT("can't append invalid menu to menubar") );
986 if ( !wxMenuBarBase::Append(menu
, title
) )
991 UMASetMenuTitle( MAC_WXHMENU(menu
->GetHMenu()) , title
, m_font
.GetEncoding() ) ;
995 if (s_macInstalledMenuBar
== this)
997 menu
->MacBeforeDisplay( false ) ;
998 ::InsertMenu( MAC_WXHMENU(menu
->GetHMenu()) , 0 ) ;
1004 // m_invokingWindow is set after wxFrame::SetMenuBar(). This call enables
1005 // adding menu later on.
1006 if (m_invokingWindow
)
1007 wxMenubarSetInvokingWindow( menu
, m_invokingWindow
);
1012 static void wxMenubarUnsetInvokingWindow( wxMenu
*menu
)
1014 menu
->SetInvokingWindow( (wxWindow
*) NULL
);
1015 wxMenuItemList::compatibility_iterator node
= menu
->GetMenuItems().GetFirst();
1019 wxMenuItem
*menuitem
= node
->GetData();
1020 if (menuitem
->IsSubMenu())
1021 wxMenubarUnsetInvokingWindow( menuitem
->GetSubMenu() );
1023 node
= node
->GetNext();
1027 static void wxMenubarSetInvokingWindow( wxMenu
*menu
, wxWindow
*win
)
1029 menu
->SetInvokingWindow( win
);
1030 wxMenuItem
*menuitem
;
1031 wxMenuItemList::compatibility_iterator node
= menu
->GetMenuItems().GetFirst();
1035 menuitem
= node
->GetData();
1036 if (menuitem
->IsSubMenu())
1037 wxMenubarSetInvokingWindow( menuitem
->GetSubMenu() , win
);
1039 node
= node
->GetNext();
1043 void wxMenuBar::UnsetInvokingWindow()
1045 m_invokingWindow
= (wxWindow
*) NULL
;
1047 wxMenuList::compatibility_iterator node
= m_menus
.GetFirst();
1051 menu
= node
->GetData();
1052 wxMenubarUnsetInvokingWindow( menu
);
1054 node
= node
->GetNext();
1058 void wxMenuBar::SetInvokingWindow(wxFrame
*frame
)
1060 m_invokingWindow
= frame
;
1062 wxMenuList::compatibility_iterator node
= m_menus
.GetFirst();
1066 menu
= node
->GetData();
1067 wxMenubarSetInvokingWindow( menu
, frame
);
1069 node
= node
->GetNext();
1073 void wxMenuBar::Detach()
1075 wxMenuBarBase::Detach() ;
1078 void wxMenuBar::Attach(wxFrame
*frame
)
1080 wxMenuBarBase::Attach( frame
) ;
1083 // ---------------------------------------------------------------------------
1084 // wxMenuBar searching for menu items
1085 // ---------------------------------------------------------------------------
1087 // Find the itemString in menuString, and return the item id or wxNOT_FOUND
1088 int wxMenuBar::FindMenuItem(const wxString
& menuString
,
1089 const wxString
& itemString
) const
1091 wxString menuLabel
= wxStripMenuCodes(menuString
);
1092 size_t count
= GetMenuCount();
1093 for ( size_t i
= 0; i
< count
; i
++ )
1095 wxString title
= wxStripMenuCodes(m_titles
[i
]);
1096 if ( menuLabel
== title
)
1097 return _wxMenuAt(m_menus
, i
)->FindItem(itemString
);
1103 wxMenuItem
*wxMenuBar::FindItem(int id
, wxMenu
**itemMenu
) const
1108 wxMenuItem
*item
= NULL
;
1109 size_t count
= GetMenuCount();
1110 for ( size_t i
= 0; !item
&& (i
< count
); i
++ )
1111 item
= _wxMenuAt(m_menus
, i
)->FindItem(id
, itemMenu
);