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 ) ;
468 // what we do here is to hide the special items which are
469 // shown in the application menu anyhow -- it doesn't make
470 // sense to show them in their normal place as well
471 if ( item
->GetId() == wxApp::s_macAboutMenuItemId
||
472 ( UMAGetSystemVersion() >= 0x1000 && (
473 item
->GetId() == wxApp::s_macPreferencesMenuItemId
||
474 item
->GetId() == wxApp::s_macExitMenuItemId
) ) )
477 ChangeMenuItemAttributes( MAC_WXHMENU( GetHMenu() ),
478 pos
+ 1, kMenuItemAttrHidden
, 0 );
480 // also check for a separator which was used just to
481 // separate this item from the others, so don't leave
482 // separator at the menu start or end nor 2 consecutive
484 wxMenuItemList::compatibility_iterator nextNode
= node
->GetNext();
485 wxMenuItem
*next
= nextNode
? nextNode
->GetData() : NULL
;
488 if ( !previousItem
&& next
&& next
->IsSeparator() )
490 // next (i.e. second as we must be first) item is
491 // the separator to hide
492 wxASSERT_MSG( pos
== 0, _T("should be the menu start") );
495 else if ( GetMenuItems().GetCount() == pos
+ 1 &&
496 previousItem
!= NULL
&&
497 previousItem
->IsSeparator() )
499 // prev item is a trailing separator we want to hide
502 else if ( previousItem
&& previousItem
->IsSeparator() &&
503 next
&& next
->IsSeparator() )
505 // two consecutive separators, this is one too many
508 else // no separators to hide
515 // hide the separator as well
516 ChangeMenuItemAttributes( MAC_WXHMENU( GetHMenu() ),
524 previousItem
= item
;
528 ::InsertMenu(MAC_WXHMENU( GetHMenu()), -1);
531 // undo all changes from the MacBeforeDisplay call
532 void wxMenu::MacAfterDisplay( bool isSubMenu
)
535 ::DeleteMenu(MacGetMenuId());
537 wxMenuItemList::compatibility_iterator node
;
540 for (node
= GetMenuItems().GetFirst(); node
; node
= node
->GetNext())
542 item
= (wxMenuItem
*)node
->GetData();
543 wxMenu
* subMenu
= item
->GetSubMenu() ;
546 subMenu
->MacAfterDisplay( true ) ;
550 // no need to undo hidings
555 wxInt32
wxMenu::MacHandleCommandProcess( wxMenuItem
* item
, int id
, wxWindow
* targetWindow
)
557 OSStatus result
= eventNotHandledErr
;
558 if (item
->IsCheckable())
559 item
->Check( !item
->IsChecked() ) ;
561 if ( SendEvent( id
, item
->IsCheckable() ? item
->IsChecked() : -1 ) )
565 if ( targetWindow
!= NULL
)
567 wxCommandEvent
event(wxEVT_COMMAND_MENU_SELECTED
, id
);
568 event
.SetEventObject(targetWindow
);
569 event
.SetInt(item
->IsCheckable() ? item
->IsChecked() : -1);
571 if ( targetWindow
->GetEventHandler()->ProcessEvent(event
) )
578 wxInt32
wxMenu::MacHandleCommandUpdateStatus( wxMenuItem
* item
, int id
, wxWindow
* targetWindow
)
580 OSStatus result
= eventNotHandledErr
;
581 wxUpdateUIEvent
event(id
);
582 event
.SetEventObject( this );
584 bool processed
= false;
586 // Try the menu's event handler
588 wxEvtHandler
*handler
= GetEventHandler();
590 processed
= handler
->ProcessEvent(event
);
593 // Try the window the menu was popped up from
594 // (and up through the hierarchy)
597 const wxMenuBase
*menu
= this;
600 wxWindow
*win
= menu
->GetInvokingWindow();
603 processed
= win
->GetEventHandler()->ProcessEvent(event
);
607 menu
= menu
->GetParent();
611 if ( !processed
&& targetWindow
!= NULL
)
613 processed
= targetWindow
->GetEventHandler()->ProcessEvent(event
);
618 // if anything changed, update the changed attribute
619 if (event
.GetSetText())
620 SetLabel(id
, event
.GetText());
621 if (event
.GetSetChecked())
622 Check(id
, event
.GetChecked());
623 if (event
.GetSetEnabled())
624 Enable(id
, event
.GetEnabled());
635 Mac Implementation note :
637 The Mac has only one global menubar, so we attempt to install the currently
638 active menubar from a frame, we currently don't take into account mdi-frames
639 which would ask for menu-merging
641 Secondly there is no mac api for changing a menubar that is not the current
642 menubar, so we have to wait for preparing the actual menubar until the
643 wxMenubar is to be used
645 We can in subsequent versions use MacInstallMenuBar to provide some sort of
646 auto-merge for MDI in case this will be necessary
650 wxMenuBar
* wxMenuBar::s_macInstalledMenuBar
= NULL
;
651 wxMenuBar
* wxMenuBar::s_macCommonMenuBar
= NULL
;
652 bool wxMenuBar::s_macAutoWindowMenu
= true ;
653 WXHMENU
wxMenuBar::s_macWindowMenuHandle
= NULL
;
655 void wxMenuBar::Init()
657 m_eventHandler
= this;
658 m_menuBarFrame
= NULL
;
659 m_invokingWindow
= (wxWindow
*) NULL
;
662 wxMenuBar::wxMenuBar()
667 wxMenuBar::wxMenuBar( long WXUNUSED(style
) )
672 wxMenuBar::wxMenuBar(size_t count
, wxMenu
*menus
[], const wxString titles
[], long WXUNUSED(style
))
676 m_titles
.Alloc(count
);
678 for ( size_t i
= 0; i
< count
; i
++ )
680 m_menus
.Append(menus
[i
]);
681 m_titles
.Add(titles
[i
]);
683 menus
[i
]->Attach(this);
687 wxMenuBar::~wxMenuBar()
689 if (s_macCommonMenuBar
== this)
690 s_macCommonMenuBar
= NULL
;
692 if (s_macInstalledMenuBar
== this)
695 s_macInstalledMenuBar
= NULL
;
699 void wxMenuBar::Refresh(bool WXUNUSED(eraseBackground
), const wxRect
*WXUNUSED(rect
))
701 wxCHECK_RET( IsAttached(), wxT("can't refresh unatteched menubar") );
706 void wxMenuBar::MacInstallMenuBar()
708 if ( s_macInstalledMenuBar
== this )
711 MenuBarHandle menubar
= NULL
;
713 #if TARGET_API_MAC_OSX
714 menubar
= NewHandleClear( 6 /* sizeof( MenuBarHeader ) */ ) ;
716 menubar
= NewHandleClear( 12 ) ;
717 (*menubar
)[3] = 0x0a ;
720 ::SetMenuBar( menubar
) ;
721 DisposeMenuBar( menubar
) ;
722 MenuHandle appleMenu
= NULL
;
724 verify_noerr( CreateNewMenu( kwxMacAppleMenuId
, 0 , &appleMenu
) ) ;
725 verify_noerr( SetMenuTitleWithCFString( appleMenu
, CFSTR( "\x14" ) ) );
727 // Add About/Preferences separator only on OS X
728 // KH/RN: Separator is always present on 10.3 but not on 10.2
729 // However, the change from 10.2 to 10.3 suggests it is preferred
730 #if TARGET_API_MAC_OSX
731 InsertMenuItemTextWithCFString( appleMenu
,
732 CFSTR(""), 0, kMenuItemAttrSeparator
, 0);
734 InsertMenuItemTextWithCFString( appleMenu
,
735 CFSTR("About..."), 0, 0, 0);
736 MacInsertMenu( appleMenu
, 0 ) ;
738 // if we have a mac help menu, clean it up before adding new items
739 MenuHandle helpMenuHandle
;
740 MenuItemIndex firstUserHelpMenuItem
;
742 if ( UMAGetHelpMenuDontCreate( &helpMenuHandle
, &firstUserHelpMenuItem
) == noErr
)
744 for ( int i
= CountMenuItems( helpMenuHandle
) ; i
>= firstUserHelpMenuItem
; --i
)
745 DeleteMenuItem( helpMenuHandle
, i
) ;
749 helpMenuHandle
= NULL
;
752 if ( UMAGetSystemVersion() >= 0x1000 && wxApp::s_macPreferencesMenuItemId
)
754 wxMenuItem
*item
= FindItem( wxApp::s_macPreferencesMenuItemId
, NULL
) ;
755 if ( item
== NULL
|| !(item
->IsEnabled()) )
756 DisableMenuCommand( NULL
, kHICommandPreferences
) ;
758 EnableMenuCommand( NULL
, kHICommandPreferences
) ;
761 // Unlike preferences which may or may not exist, the Quit item should be always
762 // enabled unless it is added by the application and then disabled, otherwise
763 // a program would be required to add an item with wxID_EXIT in order to get the
764 // Quit menu item to be enabled, which seems a bit burdensome.
765 if ( UMAGetSystemVersion() >= 0x1000 && wxApp::s_macExitMenuItemId
)
767 wxMenuItem
*item
= FindItem( wxApp::s_macExitMenuItemId
, NULL
) ;
768 if ( item
!= NULL
&& !(item
->IsEnabled()) )
769 DisableMenuCommand( NULL
, kHICommandQuit
) ;
771 EnableMenuCommand( NULL
, kHICommandQuit
) ;
774 wxString strippedHelpMenuTitle
= wxStripMenuCodes( wxApp::s_macHelpMenuTitleName
) ;
775 wxString strippedTranslatedHelpMenuTitle
= wxStripMenuCodes( wxString( _("&Help") ) ) ;
776 wxMenuList::compatibility_iterator menuIter
= m_menus
.GetFirst();
777 for (size_t i
= 0; i
< m_menus
.GetCount(); i
++, menuIter
= menuIter
->GetNext())
779 wxMenuItemList::compatibility_iterator node
;
781 wxMenu
* menu
= menuIter
->GetData() , *subMenu
= NULL
;
782 wxString strippedMenuTitle
= wxStripMenuCodes(m_titles
[i
]);
784 if ( strippedMenuTitle
== wxT("?") || strippedMenuTitle
== strippedHelpMenuTitle
|| strippedMenuTitle
== strippedTranslatedHelpMenuTitle
)
786 for (node
= menu
->GetMenuItems().GetFirst(); node
; node
= node
->GetNext())
788 item
= (wxMenuItem
*)node
->GetData();
789 subMenu
= item
->GetSubMenu() ;
792 // we don't support hierarchical menus in the help menu yet
796 if ( item
->GetId() != wxApp::s_macAboutMenuItemId
)
798 // we have found a user help menu and an item other than the about item,
799 // so we can create the mac help menu now, if we haven't created it yet
800 if ( helpMenuHandle
== NULL
)
802 if ( UMAGetHelpMenu( &helpMenuHandle
, &firstUserHelpMenuItem
) != noErr
)
804 helpMenuHandle
= NULL
;
810 if ( item
->IsSeparator() )
812 if ( helpMenuHandle
)
813 AppendMenuItemTextWithCFString( helpMenuHandle
,
814 CFSTR(""), kMenuItemAttrSeparator
, 0,NULL
);
819 entry
= wxAcceleratorEntry::Create( item
->GetItemLabel() ) ;
821 if ( item
->GetId() == wxApp::s_macAboutMenuItemId
)
823 // this will be taken care of below
827 if ( helpMenuHandle
)
829 UMAAppendMenuItem(helpMenuHandle
, wxStripMenuCodes(item
->GetItemLabel()) , wxFont::GetDefaultEncoding(), entry
);
830 SetMenuItemCommandID( helpMenuHandle
, CountMenuItems(helpMenuHandle
) , wxIdToMacCommand ( item
->GetId() ) ) ;
831 SetMenuItemRefCon( helpMenuHandle
, CountMenuItems(helpMenuHandle
) , (URefCon
) item
) ;
841 else if ( ( m_titles
[i
] == wxT("Window") || m_titles
[i
] == wxT("&Window") )
842 && GetAutoWindowMenu() )
844 if ( MacGetWindowMenuHMenu() == NULL
)
846 CreateStandardWindowMenu( 0 , (MenuHandle
*) &s_macWindowMenuHandle
) ;
849 MenuRef wm
= (MenuRef
)MacGetWindowMenuHMenu();
853 // get the insertion point in the standard menu
854 MenuItemIndex winListStart
;
855 GetIndMenuItemWithCommandID(wm
,
856 kHICommandWindowListSeparator
, 1, NULL
, &winListStart
);
858 // add a separator so that the standard items and the custom items
859 // aren't mixed together, but only if this is the first run
860 OSStatus err
= GetIndMenuItemWithCommandID(wm
,
861 'WXWM', 1, NULL
, NULL
);
863 if ( err
== menuItemNotFoundErr
)
865 InsertMenuItemTextWithCFString( wm
,
866 CFSTR(""), winListStart
-1, kMenuItemAttrSeparator
, 'WXWM');
869 wxInsertMenuItemsInMenu(menu
, wm
, winListStart
);
873 UMASetMenuTitle( MAC_WXHMENU(menu
->GetHMenu()) , m_titles
[i
], m_font
.GetEncoding() ) ;
874 menu
->MacBeforeDisplay(false) ;
876 ::InsertMenu(MAC_WXHMENU(_wxMenuAt(m_menus
, i
)->GetHMenu()), 0);
880 // take care of the about menu item wherever it is
883 wxMenuItem
*aboutMenuItem
= FindItem(wxApp::s_macAboutMenuItemId
, &aboutMenu
) ;
887 entry
= wxAcceleratorEntry::Create( aboutMenuItem
->GetItemLabel() ) ;
888 UMASetMenuItemText( GetMenuHandle( kwxMacAppleMenuId
) , 1 , wxStripMenuCodes ( aboutMenuItem
->GetItemLabel() ) , wxFont::GetDefaultEncoding() );
889 UMAEnableMenuItem( GetMenuHandle( kwxMacAppleMenuId
) , 1 , true );
890 SetMenuItemCommandID( GetMenuHandle( kwxMacAppleMenuId
) , 1 , kHICommandAbout
) ;
891 SetMenuItemRefCon(GetMenuHandle( kwxMacAppleMenuId
) , 1 , (URefCon
)aboutMenuItem
) ;
892 UMASetMenuItemShortcut( GetMenuHandle( kwxMacAppleMenuId
) , 1 , entry
) ;
896 if ( GetAutoWindowMenu() )
898 if ( MacGetWindowMenuHMenu() == NULL
)
899 CreateStandardWindowMenu( 0 , (MenuHandle
*) &s_macWindowMenuHandle
) ;
901 InsertMenu( (MenuHandle
) MacGetWindowMenuHMenu() , 0 ) ;
905 s_macInstalledMenuBar
= this;
908 void wxMenuBar::EnableTop(size_t pos
, bool enable
)
910 wxCHECK_RET( IsAttached(), wxT("doesn't work with unattached menubars") );
912 _wxMenuAt(m_menus
, pos
)->MacEnableMenu( enable
) ;
916 bool wxMenuBar::Enable(bool enable
)
918 wxCHECK_MSG( IsAttached(), false, wxT("doesn't work with unattached menubars") );
921 for (i
= 0; i
< GetMenuCount(); i
++)
922 EnableTop(i
, enable
);
927 void wxMenuBar::SetMenuLabel(size_t pos
, const wxString
& label
)
929 wxCHECK_RET( pos
< GetMenuCount(), wxT("invalid menu index") );
931 m_titles
[pos
] = label
;
936 _wxMenuAt(m_menus
, pos
)->SetTitle( label
) ;
938 if (wxMenuBar::s_macInstalledMenuBar
== this) // are we currently installed ?
940 ::SetMenuBar( GetMenuBar() ) ;
945 wxString
wxMenuBar::GetMenuLabel(size_t pos
) const
947 wxCHECK_MSG( pos
< GetMenuCount(), wxEmptyString
,
948 wxT("invalid menu index in wxMenuBar::GetMenuLabel") );
950 return m_titles
[pos
];
953 int wxMenuBar::FindMenu(const wxString
& title
)
955 wxString menuTitle
= wxStripMenuCodes(title
);
957 size_t count
= GetMenuCount();
958 for ( size_t i
= 0; i
< count
; i
++ )
960 wxString title
= wxStripMenuCodes(m_titles
[i
]);
961 if ( menuTitle
== title
)
968 // ---------------------------------------------------------------------------
969 // wxMenuBar construction
970 // ---------------------------------------------------------------------------
972 wxMenu
*wxMenuBar::Replace(size_t pos
, wxMenu
*menu
, const wxString
& title
)
974 wxMenu
*menuOld
= wxMenuBarBase::Replace(pos
, menu
, title
);
978 m_titles
[pos
] = title
;
982 if (s_macInstalledMenuBar
== this)
984 menuOld
->MacAfterDisplay( false ) ;
985 ::DeleteMenu( menuOld
->MacGetMenuId() /* m_menus[pos]->MacGetMenuId() */ ) ;
987 menu
->MacBeforeDisplay( false ) ;
988 UMASetMenuTitle( MAC_WXHMENU(menu
->GetHMenu()) , title
, m_font
.GetEncoding() ) ;
989 if ( pos
== m_menus
.GetCount() - 1)
990 ::InsertMenu( MAC_WXHMENU(menu
->GetHMenu()) , 0 ) ;
992 ::InsertMenu( MAC_WXHMENU(menu
->GetHMenu()) , _wxMenuAt(m_menus
, pos
+ 1)->MacGetMenuId() ) ;
998 if (m_invokingWindow
)
999 wxMenubarSetInvokingWindow( menu
, m_invokingWindow
);
1004 bool wxMenuBar::Insert(size_t pos
, wxMenu
*menu
, const wxString
& title
)
1006 if ( !wxMenuBarBase::Insert(pos
, menu
, title
) )
1009 m_titles
.Insert(title
, pos
);
1011 UMASetMenuTitle( MAC_WXHMENU(menu
->GetHMenu()) , title
, m_font
.GetEncoding() ) ;
1013 if ( IsAttached() && s_macInstalledMenuBar
== this )
1015 if (s_macInstalledMenuBar
== this)
1017 menu
->MacBeforeDisplay( false ) ;
1019 if ( pos
== (size_t) -1 || pos
+ 1 == m_menus
.GetCount() )
1020 ::InsertMenu( MAC_WXHMENU(menu
->GetHMenu()) , 0 ) ;
1022 ::InsertMenu( MAC_WXHMENU(menu
->GetHMenu()) , _wxMenuAt(m_menus
, pos
+1)->MacGetMenuId() ) ;
1028 if (m_invokingWindow
)
1029 wxMenubarSetInvokingWindow( menu
, m_invokingWindow
);
1034 wxMenu
*wxMenuBar::Remove(size_t pos
)
1036 wxMenu
*menu
= wxMenuBarBase::Remove(pos
);
1042 if (s_macInstalledMenuBar
== this)
1043 ::DeleteMenu( menu
->MacGetMenuId() /* m_menus[pos]->MacGetMenuId() */ ) ;
1048 m_titles
.RemoveAt(pos
);
1053 bool wxMenuBar::Append(wxMenu
*menu
, const wxString
& title
)
1055 WXHMENU submenu
= menu
? menu
->GetHMenu() : 0;
1056 wxCHECK_MSG( submenu
, false, wxT("can't append invalid menu to menubar") );
1058 if ( !wxMenuBarBase::Append(menu
, title
) )
1061 m_titles
.Add(title
);
1063 UMASetMenuTitle( MAC_WXHMENU(menu
->GetHMenu()) , title
, m_font
.GetEncoding() ) ;
1067 if (s_macInstalledMenuBar
== this)
1069 menu
->MacBeforeDisplay( false ) ;
1070 ::InsertMenu( MAC_WXHMENU(menu
->GetHMenu()) , 0 ) ;
1076 // m_invokingWindow is set after wxFrame::SetMenuBar(). This call enables
1077 // adding menu later on.
1078 if (m_invokingWindow
)
1079 wxMenubarSetInvokingWindow( menu
, m_invokingWindow
);
1084 static void wxMenubarUnsetInvokingWindow( wxMenu
*menu
)
1086 menu
->SetInvokingWindow( (wxWindow
*) NULL
);
1087 wxMenuItemList::compatibility_iterator node
= menu
->GetMenuItems().GetFirst();
1091 wxMenuItem
*menuitem
= node
->GetData();
1092 if (menuitem
->IsSubMenu())
1093 wxMenubarUnsetInvokingWindow( menuitem
->GetSubMenu() );
1095 node
= node
->GetNext();
1099 static void wxMenubarSetInvokingWindow( wxMenu
*menu
, wxWindow
*win
)
1101 menu
->SetInvokingWindow( win
);
1102 wxMenuItem
*menuitem
;
1103 wxMenuItemList::compatibility_iterator node
= menu
->GetMenuItems().GetFirst();
1107 menuitem
= node
->GetData();
1108 if (menuitem
->IsSubMenu())
1109 wxMenubarSetInvokingWindow( menuitem
->GetSubMenu() , win
);
1111 node
= node
->GetNext();
1115 void wxMenuBar::UnsetInvokingWindow()
1117 m_invokingWindow
= (wxWindow
*) NULL
;
1119 wxMenuList::compatibility_iterator node
= m_menus
.GetFirst();
1123 menu
= node
->GetData();
1124 wxMenubarUnsetInvokingWindow( menu
);
1126 node
= node
->GetNext();
1130 void wxMenuBar::SetInvokingWindow(wxFrame
*frame
)
1132 m_invokingWindow
= frame
;
1134 wxMenuList::compatibility_iterator node
= m_menus
.GetFirst();
1138 menu
= node
->GetData();
1139 wxMenubarSetInvokingWindow( menu
, frame
);
1141 node
= node
->GetNext();
1145 void wxMenuBar::Detach()
1147 wxMenuBarBase::Detach() ;
1150 void wxMenuBar::Attach(wxFrame
*frame
)
1152 wxMenuBarBase::Attach( frame
) ;
1155 // ---------------------------------------------------------------------------
1156 // wxMenuBar searching for menu items
1157 // ---------------------------------------------------------------------------
1159 // Find the itemString in menuString, and return the item id or wxNOT_FOUND
1160 int wxMenuBar::FindMenuItem(const wxString
& menuString
,
1161 const wxString
& itemString
) const
1163 wxString menuLabel
= wxStripMenuCodes(menuString
);
1164 size_t count
= GetMenuCount();
1165 for ( size_t i
= 0; i
< count
; i
++ )
1167 wxString title
= wxStripMenuCodes(m_titles
[i
]);
1168 if ( menuLabel
== title
)
1169 return _wxMenuAt(m_menus
, i
)->FindItem(itemString
);
1175 wxMenuItem
*wxMenuBar::FindItem(int id
, wxMenu
**itemMenu
) const
1180 wxMenuItem
*item
= NULL
;
1181 size_t count
= GetMenuCount();
1182 for ( size_t i
= 0; !item
&& (i
< count
); i
++ )
1183 item
= _wxMenuAt(m_menus
, i
)->FindItem(id
, itemMenu
);