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 item
->GetId() == wxApp::s_macPreferencesMenuItemId
||
473 item
->GetId() == wxApp::s_macExitMenuItemId
)
476 ChangeMenuItemAttributes( MAC_WXHMENU( GetHMenu() ),
477 pos
+ 1, kMenuItemAttrHidden
, 0 );
479 // also check for a separator which was used just to
480 // separate this item from the others, so don't leave
481 // separator at the menu start or end nor 2 consecutive
483 wxMenuItemList::compatibility_iterator nextNode
= node
->GetNext();
484 wxMenuItem
*next
= nextNode
? nextNode
->GetData() : NULL
;
487 if ( !previousItem
&& next
&& next
->IsSeparator() )
489 // next (i.e. second as we must be first) item is
490 // the separator to hide
491 wxASSERT_MSG( pos
== 0, _T("should be the menu start") );
494 else if ( GetMenuItems().GetCount() == pos
+ 1 &&
495 previousItem
!= NULL
&&
496 previousItem
->IsSeparator() )
498 // prev item is a trailing separator we want to hide
501 else if ( previousItem
&& previousItem
->IsSeparator() &&
502 next
&& next
->IsSeparator() )
504 // two consecutive separators, this is one too many
507 else // no separators to hide
514 // hide the separator as well
515 ChangeMenuItemAttributes( MAC_WXHMENU( GetHMenu() ),
523 previousItem
= item
;
527 ::InsertMenu(MAC_WXHMENU( GetHMenu()), -1);
530 // undo all changes from the MacBeforeDisplay call
531 void wxMenu::MacAfterDisplay( bool isSubMenu
)
534 ::DeleteMenu(MacGetMenuId());
536 wxMenuItemList::compatibility_iterator node
;
539 for (node
= GetMenuItems().GetFirst(); node
; node
= node
->GetNext())
541 item
= (wxMenuItem
*)node
->GetData();
542 wxMenu
* subMenu
= item
->GetSubMenu() ;
545 subMenu
->MacAfterDisplay( true ) ;
549 // no need to undo hidings
554 wxInt32
wxMenu::MacHandleCommandProcess( wxMenuItem
* item
, int id
, wxWindow
* targetWindow
)
556 OSStatus result
= eventNotHandledErr
;
557 if (item
->IsCheckable())
558 item
->Check( !item
->IsChecked() ) ;
560 if ( SendEvent( id
, item
->IsCheckable() ? item
->IsChecked() : -1 ) )
564 if ( targetWindow
!= NULL
)
566 wxCommandEvent
event(wxEVT_COMMAND_MENU_SELECTED
, id
);
567 event
.SetEventObject(targetWindow
);
568 event
.SetInt(item
->IsCheckable() ? item
->IsChecked() : -1);
570 if ( targetWindow
->GetEventHandler()->ProcessEvent(event
) )
577 wxInt32
wxMenu::MacHandleCommandUpdateStatus(wxMenuItem
* WXUNUSED(item
),
579 wxWindow
* targetWindow
)
581 OSStatus result
= eventNotHandledErr
;
582 wxUpdateUIEvent
event(id
);
583 event
.SetEventObject( this );
585 bool processed
= false;
587 // Try the menu's event handler
589 wxEvtHandler
*handler
= GetEventHandler();
591 processed
= handler
->ProcessEvent(event
);
594 // Try the window the menu was popped up from
595 // (and up through the hierarchy)
598 const wxMenuBase
*menu
= this;
601 wxWindow
*win
= menu
->GetInvokingWindow();
604 processed
= win
->GetEventHandler()->ProcessEvent(event
);
608 menu
= menu
->GetParent();
612 if ( !processed
&& targetWindow
!= NULL
)
614 processed
= targetWindow
->GetEventHandler()->ProcessEvent(event
);
619 // if anything changed, update the changed attribute
620 if (event
.GetSetText())
621 SetLabel(id
, event
.GetText());
622 if (event
.GetSetChecked())
623 Check(id
, event
.GetChecked());
624 if (event
.GetSetEnabled())
625 Enable(id
, event
.GetEnabled());
636 Mac Implementation note :
638 The Mac has only one global menubar, so we attempt to install the currently
639 active menubar from a frame, we currently don't take into account mdi-frames
640 which would ask for menu-merging
642 Secondly there is no mac api for changing a menubar that is not the current
643 menubar, so we have to wait for preparing the actual menubar until the
644 wxMenubar is to be used
646 We can in subsequent versions use MacInstallMenuBar to provide some sort of
647 auto-merge for MDI in case this will be necessary
651 wxMenuBar
* wxMenuBar::s_macInstalledMenuBar
= NULL
;
652 wxMenuBar
* wxMenuBar::s_macCommonMenuBar
= NULL
;
653 bool wxMenuBar::s_macAutoWindowMenu
= true ;
654 WXHMENU
wxMenuBar::s_macWindowMenuHandle
= NULL
;
656 void wxMenuBar::Init()
658 m_eventHandler
= this;
659 m_menuBarFrame
= NULL
;
660 m_invokingWindow
= (wxWindow
*) NULL
;
663 wxMenuBar::wxMenuBar()
668 wxMenuBar::wxMenuBar( long WXUNUSED(style
) )
673 wxMenuBar::wxMenuBar(size_t count
, wxMenu
*menus
[], const wxString titles
[], long WXUNUSED(style
))
677 m_titles
.Alloc(count
);
679 for ( size_t i
= 0; i
< count
; i
++ )
681 m_menus
.Append(menus
[i
]);
682 m_titles
.Add(titles
[i
]);
684 menus
[i
]->Attach(this);
688 wxMenuBar::~wxMenuBar()
690 if (s_macCommonMenuBar
== this)
691 s_macCommonMenuBar
= NULL
;
693 if (s_macInstalledMenuBar
== this)
696 s_macInstalledMenuBar
= NULL
;
700 void wxMenuBar::Refresh(bool WXUNUSED(eraseBackground
), const wxRect
*WXUNUSED(rect
))
702 wxCHECK_RET( IsAttached(), wxT("can't refresh unatteched menubar") );
707 void wxMenuBar::MacInstallMenuBar()
709 if ( s_macInstalledMenuBar
== this )
712 MenuBarHandle menubar
= NULL
;
714 #if TARGET_API_MAC_OSX
715 menubar
= NewHandleClear( 6 /* sizeof( MenuBarHeader ) */ ) ;
717 menubar
= NewHandleClear( 12 ) ;
718 (*menubar
)[3] = 0x0a ;
721 ::SetMenuBar( menubar
) ;
722 DisposeMenuBar( menubar
) ;
723 MenuHandle appleMenu
= NULL
;
725 verify_noerr( CreateNewMenu( kwxMacAppleMenuId
, 0 , &appleMenu
) ) ;
726 verify_noerr( SetMenuTitleWithCFString( appleMenu
, CFSTR( "\x14" ) ) );
728 // Add About/Preferences separator only on OS X
729 // KH/RN: Separator is always present on 10.3 but not on 10.2
730 // However, the change from 10.2 to 10.3 suggests it is preferred
731 #if TARGET_API_MAC_OSX
732 InsertMenuItemTextWithCFString( appleMenu
,
733 CFSTR(""), 0, kMenuItemAttrSeparator
, 0);
735 InsertMenuItemTextWithCFString( appleMenu
,
736 CFSTR("About..."), 0, 0, 0);
737 MacInsertMenu( appleMenu
, 0 ) ;
739 // if we have a mac help menu, clean it up before adding new items
740 MenuHandle helpMenuHandle
;
741 MenuItemIndex firstUserHelpMenuItem
;
743 if ( UMAGetHelpMenuDontCreate( &helpMenuHandle
, &firstUserHelpMenuItem
) == noErr
)
745 for ( int i
= CountMenuItems( helpMenuHandle
) ; i
>= firstUserHelpMenuItem
; --i
)
746 DeleteMenuItem( helpMenuHandle
, i
) ;
750 helpMenuHandle
= NULL
;
753 if ( wxApp::s_macPreferencesMenuItemId
)
755 wxMenuItem
*item
= FindItem( wxApp::s_macPreferencesMenuItemId
, NULL
) ;
756 if ( item
== NULL
|| !(item
->IsEnabled()) )
757 DisableMenuCommand( NULL
, kHICommandPreferences
) ;
759 EnableMenuCommand( NULL
, kHICommandPreferences
) ;
762 // Unlike preferences which may or may not exist, the Quit item should be always
763 // enabled unless it is added by the application and then disabled, otherwise
764 // a program would be required to add an item with wxID_EXIT in order to get the
765 // Quit menu item to be enabled, which seems a bit burdensome.
766 if ( wxApp::s_macExitMenuItemId
)
768 wxMenuItem
*item
= FindItem( wxApp::s_macExitMenuItemId
, NULL
) ;
769 if ( item
!= NULL
&& !(item
->IsEnabled()) )
770 DisableMenuCommand( NULL
, kHICommandQuit
) ;
772 EnableMenuCommand( NULL
, kHICommandQuit
) ;
775 wxString strippedHelpMenuTitle
= wxStripMenuCodes( wxApp::s_macHelpMenuTitleName
) ;
776 wxString strippedTranslatedHelpMenuTitle
= wxStripMenuCodes( wxString( _("&Help") ) ) ;
777 wxMenuList::compatibility_iterator menuIter
= m_menus
.GetFirst();
778 for (size_t i
= 0; i
< m_menus
.GetCount(); i
++, menuIter
= menuIter
->GetNext())
780 wxMenuItemList::compatibility_iterator node
;
782 wxMenu
* menu
= menuIter
->GetData() , *subMenu
= NULL
;
783 wxString strippedMenuTitle
= wxStripMenuCodes(m_titles
[i
]);
785 if ( strippedMenuTitle
== wxT("?") || strippedMenuTitle
== strippedHelpMenuTitle
|| strippedMenuTitle
== strippedTranslatedHelpMenuTitle
)
787 for (node
= menu
->GetMenuItems().GetFirst(); node
; node
= node
->GetNext())
789 item
= (wxMenuItem
*)node
->GetData();
790 subMenu
= item
->GetSubMenu() ;
793 // we don't support hierarchical menus in the help menu yet
797 if ( item
->GetId() != wxApp::s_macAboutMenuItemId
)
799 // we have found a user help menu and an item other than the about item,
800 // so we can create the mac help menu now, if we haven't created it yet
801 if ( helpMenuHandle
== NULL
)
803 if ( UMAGetHelpMenu( &helpMenuHandle
, &firstUserHelpMenuItem
) != noErr
)
805 helpMenuHandle
= NULL
;
811 if ( item
->IsSeparator() )
813 if ( helpMenuHandle
)
814 AppendMenuItemTextWithCFString( helpMenuHandle
,
815 CFSTR(""), kMenuItemAttrSeparator
, 0,NULL
);
820 entry
= wxAcceleratorEntry::Create( item
->GetItemLabel() ) ;
822 if ( item
->GetId() == wxApp::s_macAboutMenuItemId
)
824 // this will be taken care of below
828 if ( helpMenuHandle
)
830 UMAAppendMenuItem(helpMenuHandle
, wxStripMenuCodes(item
->GetItemLabel()) , wxFont::GetDefaultEncoding(), entry
);
831 SetMenuItemCommandID( helpMenuHandle
, CountMenuItems(helpMenuHandle
) , wxIdToMacCommand ( item
->GetId() ) ) ;
832 SetMenuItemRefCon( helpMenuHandle
, CountMenuItems(helpMenuHandle
) , (URefCon
) item
) ;
842 else if ( ( m_titles
[i
] == wxT("Window") || m_titles
[i
] == wxT("&Window") )
843 && GetAutoWindowMenu() )
845 if ( MacGetWindowMenuHMenu() == NULL
)
847 CreateStandardWindowMenu( 0 , (MenuHandle
*) &s_macWindowMenuHandle
) ;
850 MenuRef wm
= (MenuRef
)MacGetWindowMenuHMenu();
854 // get the insertion point in the standard menu
855 MenuItemIndex winListStart
;
856 GetIndMenuItemWithCommandID(wm
,
857 kHICommandWindowListSeparator
, 1, NULL
, &winListStart
);
859 // add a separator so that the standard items and the custom items
860 // aren't mixed together, but only if this is the first run
861 OSStatus err
= GetIndMenuItemWithCommandID(wm
,
862 'WXWM', 1, NULL
, NULL
);
864 if ( err
== menuItemNotFoundErr
)
866 InsertMenuItemTextWithCFString( wm
,
867 CFSTR(""), winListStart
-1, kMenuItemAttrSeparator
, 'WXWM');
870 wxInsertMenuItemsInMenu(menu
, wm
, winListStart
);
874 UMASetMenuTitle( MAC_WXHMENU(menu
->GetHMenu()) , m_titles
[i
], m_font
.GetEncoding() ) ;
875 menu
->MacBeforeDisplay(false) ;
877 ::InsertMenu(MAC_WXHMENU(_wxMenuAt(m_menus
, i
)->GetHMenu()), 0);
881 // take care of the about menu item wherever it is
884 wxMenuItem
*aboutMenuItem
= FindItem(wxApp::s_macAboutMenuItemId
, &aboutMenu
) ;
888 entry
= wxAcceleratorEntry::Create( aboutMenuItem
->GetItemLabel() ) ;
889 UMASetMenuItemText( GetMenuHandle( kwxMacAppleMenuId
) , 1 , wxStripMenuCodes ( aboutMenuItem
->GetItemLabel() ) , wxFont::GetDefaultEncoding() );
890 UMAEnableMenuItem( GetMenuHandle( kwxMacAppleMenuId
) , 1 , true );
891 SetMenuItemCommandID( GetMenuHandle( kwxMacAppleMenuId
) , 1 , kHICommandAbout
) ;
892 SetMenuItemRefCon(GetMenuHandle( kwxMacAppleMenuId
) , 1 , (URefCon
)aboutMenuItem
) ;
893 UMASetMenuItemShortcut( GetMenuHandle( kwxMacAppleMenuId
) , 1 , entry
) ;
897 if ( GetAutoWindowMenu() )
899 if ( MacGetWindowMenuHMenu() == NULL
)
900 CreateStandardWindowMenu( 0 , (MenuHandle
*) &s_macWindowMenuHandle
) ;
902 InsertMenu( (MenuHandle
) MacGetWindowMenuHMenu() , 0 ) ;
906 s_macInstalledMenuBar
= this;
909 void wxMenuBar::EnableTop(size_t pos
, bool enable
)
911 wxCHECK_RET( IsAttached(), wxT("doesn't work with unattached menubars") );
913 _wxMenuAt(m_menus
, pos
)->MacEnableMenu( enable
) ;
917 bool wxMenuBar::Enable(bool enable
)
919 wxCHECK_MSG( IsAttached(), false, wxT("doesn't work with unattached menubars") );
922 for (i
= 0; i
< GetMenuCount(); i
++)
923 EnableTop(i
, enable
);
928 void wxMenuBar::SetMenuLabel(size_t pos
, const wxString
& label
)
930 wxCHECK_RET( pos
< GetMenuCount(), wxT("invalid menu index") );
932 m_titles
[pos
] = label
;
937 _wxMenuAt(m_menus
, pos
)->SetTitle( label
) ;
939 if (wxMenuBar::s_macInstalledMenuBar
== this) // are we currently installed ?
941 ::SetMenuBar( GetMenuBar() ) ;
946 wxString
wxMenuBar::GetMenuLabel(size_t pos
) const
948 wxCHECK_MSG( pos
< GetMenuCount(), wxEmptyString
,
949 wxT("invalid menu index in wxMenuBar::GetMenuLabel") );
951 return m_titles
[pos
];
954 int wxMenuBar::FindMenu(const wxString
& title
)
956 wxString menuTitle
= wxStripMenuCodes(title
);
958 size_t count
= GetMenuCount();
959 for ( size_t i
= 0; i
< count
; i
++ )
961 wxString title
= wxStripMenuCodes(m_titles
[i
]);
962 if ( menuTitle
== title
)
969 // ---------------------------------------------------------------------------
970 // wxMenuBar construction
971 // ---------------------------------------------------------------------------
973 wxMenu
*wxMenuBar::Replace(size_t pos
, wxMenu
*menu
, const wxString
& title
)
975 wxMenu
*menuOld
= wxMenuBarBase::Replace(pos
, menu
, title
);
979 m_titles
[pos
] = title
;
983 if (s_macInstalledMenuBar
== this)
985 menuOld
->MacAfterDisplay( false ) ;
986 ::DeleteMenu( menuOld
->MacGetMenuId() /* m_menus[pos]->MacGetMenuId() */ ) ;
988 menu
->MacBeforeDisplay( false ) ;
989 UMASetMenuTitle( MAC_WXHMENU(menu
->GetHMenu()) , title
, m_font
.GetEncoding() ) ;
990 if ( pos
== m_menus
.GetCount() - 1)
991 ::InsertMenu( MAC_WXHMENU(menu
->GetHMenu()) , 0 ) ;
993 ::InsertMenu( MAC_WXHMENU(menu
->GetHMenu()) , _wxMenuAt(m_menus
, pos
+ 1)->MacGetMenuId() ) ;
999 if (m_invokingWindow
)
1000 wxMenubarSetInvokingWindow( menu
, m_invokingWindow
);
1005 bool wxMenuBar::Insert(size_t pos
, wxMenu
*menu
, const wxString
& title
)
1007 if ( !wxMenuBarBase::Insert(pos
, menu
, title
) )
1010 m_titles
.Insert(title
, pos
);
1012 UMASetMenuTitle( MAC_WXHMENU(menu
->GetHMenu()) , title
, m_font
.GetEncoding() ) ;
1014 if ( IsAttached() && s_macInstalledMenuBar
== this )
1016 if (s_macInstalledMenuBar
== this)
1018 menu
->MacBeforeDisplay( false ) ;
1020 if ( pos
== (size_t) -1 || pos
+ 1 == m_menus
.GetCount() )
1021 ::InsertMenu( MAC_WXHMENU(menu
->GetHMenu()) , 0 ) ;
1023 ::InsertMenu( MAC_WXHMENU(menu
->GetHMenu()) , _wxMenuAt(m_menus
, pos
+1)->MacGetMenuId() ) ;
1029 if (m_invokingWindow
)
1030 wxMenubarSetInvokingWindow( menu
, m_invokingWindow
);
1035 wxMenu
*wxMenuBar::Remove(size_t pos
)
1037 wxMenu
*menu
= wxMenuBarBase::Remove(pos
);
1043 if (s_macInstalledMenuBar
== this)
1044 ::DeleteMenu( menu
->MacGetMenuId() /* m_menus[pos]->MacGetMenuId() */ ) ;
1049 m_titles
.RemoveAt(pos
);
1054 bool wxMenuBar::Append(wxMenu
*menu
, const wxString
& title
)
1056 WXHMENU submenu
= menu
? menu
->GetHMenu() : 0;
1057 wxCHECK_MSG( submenu
, false, wxT("can't append invalid menu to menubar") );
1059 if ( !wxMenuBarBase::Append(menu
, title
) )
1062 m_titles
.Add(title
);
1064 UMASetMenuTitle( MAC_WXHMENU(menu
->GetHMenu()) , title
, m_font
.GetEncoding() ) ;
1068 if (s_macInstalledMenuBar
== this)
1070 menu
->MacBeforeDisplay( false ) ;
1071 ::InsertMenu( MAC_WXHMENU(menu
->GetHMenu()) , 0 ) ;
1077 // m_invokingWindow is set after wxFrame::SetMenuBar(). This call enables
1078 // adding menu later on.
1079 if (m_invokingWindow
)
1080 wxMenubarSetInvokingWindow( menu
, m_invokingWindow
);
1085 static void wxMenubarUnsetInvokingWindow( wxMenu
*menu
)
1087 menu
->SetInvokingWindow( (wxWindow
*) NULL
);
1088 wxMenuItemList::compatibility_iterator node
= menu
->GetMenuItems().GetFirst();
1092 wxMenuItem
*menuitem
= node
->GetData();
1093 if (menuitem
->IsSubMenu())
1094 wxMenubarUnsetInvokingWindow( menuitem
->GetSubMenu() );
1096 node
= node
->GetNext();
1100 static void wxMenubarSetInvokingWindow( wxMenu
*menu
, wxWindow
*win
)
1102 menu
->SetInvokingWindow( win
);
1103 wxMenuItem
*menuitem
;
1104 wxMenuItemList::compatibility_iterator node
= menu
->GetMenuItems().GetFirst();
1108 menuitem
= node
->GetData();
1109 if (menuitem
->IsSubMenu())
1110 wxMenubarSetInvokingWindow( menuitem
->GetSubMenu() , win
);
1112 node
= node
->GetNext();
1116 void wxMenuBar::UnsetInvokingWindow()
1118 m_invokingWindow
= (wxWindow
*) NULL
;
1120 wxMenuList::compatibility_iterator node
= m_menus
.GetFirst();
1124 menu
= node
->GetData();
1125 wxMenubarUnsetInvokingWindow( menu
);
1127 node
= node
->GetNext();
1131 void wxMenuBar::SetInvokingWindow(wxFrame
*frame
)
1133 m_invokingWindow
= frame
;
1135 wxMenuList::compatibility_iterator node
= m_menus
.GetFirst();
1139 menu
= node
->GetData();
1140 wxMenubarSetInvokingWindow( menu
, frame
);
1142 node
= node
->GetNext();
1146 void wxMenuBar::Detach()
1148 wxMenuBarBase::Detach() ;
1151 void wxMenuBar::Attach(wxFrame
*frame
)
1153 wxMenuBarBase::Attach( frame
) ;
1156 // ---------------------------------------------------------------------------
1157 // wxMenuBar searching for menu items
1158 // ---------------------------------------------------------------------------
1160 // Find the itemString in menuString, and return the item id or wxNOT_FOUND
1161 int wxMenuBar::FindMenuItem(const wxString
& menuString
,
1162 const wxString
& itemString
) const
1164 wxString menuLabel
= wxStripMenuCodes(menuString
);
1165 size_t count
= GetMenuCount();
1166 for ( size_t i
= 0; i
< count
; i
++ )
1168 wxString title
= wxStripMenuCodes(m_titles
[i
]);
1169 if ( menuLabel
== title
)
1170 return _wxMenuAt(m_menus
, i
)->FindItem(itemString
);
1176 wxMenuItem
*wxMenuBar::FindItem(int id
, wxMenu
**itemMenu
) const
1181 wxMenuItem
*item
= NULL
;
1182 size_t count
= GetMenuCount();
1183 for ( size_t i
= 0; !item
&& (i
< count
); i
++ )
1184 item
= _wxMenuAt(m_menus
, i
)->FindItem(id
, itemMenu
);