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
557 wxInt32
wxMenu::MacHandleCommandProcess( wxMenuItem
* item
, int id
, wxWindow
* targetWindow
)
559 OSStatus result
= eventNotHandledErr
;
560 if (item
->IsCheckable())
561 item
->Check( !item
->IsChecked() ) ;
563 if ( SendEvent( id
, item
->IsCheckable() ? item
->IsChecked() : -1 ) )
567 if ( targetWindow
!= NULL
)
569 wxCommandEvent
event(wxEVT_COMMAND_MENU_SELECTED
, id
);
570 event
.SetEventObject(targetWindow
);
571 event
.SetInt(item
->IsCheckable() ? item
->IsChecked() : -1);
573 if ( targetWindow
->GetEventHandler()->ProcessEvent(event
) )
580 wxInt32
wxMenu::MacHandleCommandUpdateStatus( wxMenuItem
* item
, int id
, wxWindow
* targetWindow
)
582 OSStatus result
= eventNotHandledErr
;
583 wxUpdateUIEvent
event(id
);
584 event
.SetEventObject( this );
586 bool processed
= false;
588 // Try the menu's event handler
590 wxEvtHandler
*handler
= GetEventHandler();
592 processed
= handler
->ProcessEvent(event
);
595 // Try the window the menu was popped up from
596 // (and up through the hierarchy)
599 const wxMenuBase
*menu
= this;
602 wxWindow
*win
= menu
->GetInvokingWindow();
605 processed
= win
->GetEventHandler()->ProcessEvent(event
);
609 menu
= menu
->GetParent();
613 if ( !processed
&& targetWindow
!= NULL
)
615 processed
= targetWindow
->GetEventHandler()->ProcessEvent(event
);
620 // if anything changed, update the changed attribute
621 if (event
.GetSetText())
622 SetLabel(id
, event
.GetText());
623 if (event
.GetSetChecked())
624 Check(id
, event
.GetChecked());
625 if (event
.GetSetEnabled())
626 Enable(id
, event
.GetEnabled());
637 Mac Implementation note :
639 The Mac has only one global menubar, so we attempt to install the currently
640 active menubar from a frame, we currently don't take into account mdi-frames
641 which would ask for menu-merging
643 Secondly there is no mac api for changing a menubar that is not the current
644 menubar, so we have to wait for preparing the actual menubar until the
645 wxMenubar is to be used
647 We can in subsequent versions use MacInstallMenuBar to provide some sort of
648 auto-merge for MDI in case this will be necessary
652 wxMenuBar
* wxMenuBar::s_macInstalledMenuBar
= NULL
;
653 wxMenuBar
* wxMenuBar::s_macCommonMenuBar
= NULL
;
654 bool wxMenuBar::s_macAutoWindowMenu
= true ;
655 WXHMENU
wxMenuBar::s_macWindowMenuHandle
= NULL
;
657 void wxMenuBar::Init()
659 m_eventHandler
= this;
660 m_menuBarFrame
= NULL
;
661 m_invokingWindow
= (wxWindow
*) NULL
;
664 wxMenuBar::wxMenuBar()
669 wxMenuBar::wxMenuBar( long WXUNUSED(style
) )
674 wxMenuBar::wxMenuBar(size_t count
, wxMenu
*menus
[], const wxString titles
[], long WXUNUSED(style
))
678 m_titles
.Alloc(count
);
680 for ( size_t i
= 0; i
< count
; i
++ )
682 m_menus
.Append(menus
[i
]);
683 m_titles
.Add(titles
[i
]);
685 menus
[i
]->Attach(this);
689 wxMenuBar::~wxMenuBar()
691 if (s_macCommonMenuBar
== this)
692 s_macCommonMenuBar
= NULL
;
694 if (s_macInstalledMenuBar
== this)
697 s_macInstalledMenuBar
= NULL
;
701 void wxMenuBar::Refresh(bool WXUNUSED(eraseBackground
), const wxRect
*WXUNUSED(rect
))
703 wxCHECK_RET( IsAttached(), wxT("can't refresh unatteched menubar") );
708 void wxMenuBar::MacInstallMenuBar()
710 if ( s_macInstalledMenuBar
== this )
713 MenuBarHandle menubar
= NULL
;
715 #if TARGET_API_MAC_OSX
716 menubar
= NewHandleClear( 6 /* sizeof( MenuBarHeader ) */ ) ;
718 menubar
= NewHandleClear( 12 ) ;
719 (*menubar
)[3] = 0x0a ;
722 ::SetMenuBar( menubar
) ;
723 DisposeMenuBar( menubar
) ;
724 MenuHandle appleMenu
= NULL
;
726 verify_noerr( CreateNewMenu( kwxMacAppleMenuId
, 0 , &appleMenu
) ) ;
727 verify_noerr( SetMenuTitleWithCFString( appleMenu
, CFSTR( "\x14" ) ) );
729 // Add About/Preferences separator only on OS X
730 // KH/RN: Separator is always present on 10.3 but not on 10.2
731 // However, the change from 10.2 to 10.3 suggests it is preferred
732 #if TARGET_API_MAC_OSX
733 InsertMenuItemTextWithCFString( appleMenu
,
734 CFSTR(""), 0, kMenuItemAttrSeparator
, 0);
736 InsertMenuItemTextWithCFString( appleMenu
,
737 CFSTR("About..."), 0, 0, 0);
738 MacInsertMenu( appleMenu
, 0 ) ;
740 // if we have a mac help menu, clean it up before adding new items
741 MenuHandle helpMenuHandle
;
742 MenuItemIndex firstUserHelpMenuItem
;
744 if ( UMAGetHelpMenuDontCreate( &helpMenuHandle
, &firstUserHelpMenuItem
) == noErr
)
746 for ( int i
= CountMenuItems( helpMenuHandle
) ; i
>= firstUserHelpMenuItem
; --i
)
747 DeleteMenuItem( helpMenuHandle
, i
) ;
751 helpMenuHandle
= NULL
;
755 if ( UMAGetSystemVersion() >= 0x1000 && wxApp::s_macPreferencesMenuItemId
)
757 wxMenuItem
*item
= FindItem( wxApp::s_macPreferencesMenuItemId
, NULL
) ;
758 if ( item
== NULL
|| !(item
->IsEnabled()) )
759 DisableMenuCommand( NULL
, kHICommandPreferences
) ;
761 EnableMenuCommand( NULL
, kHICommandPreferences
) ;
764 // Unlike preferences which may or may not exist, the Quit item should be always
765 // enabled unless it is added by the application and then disabled, otherwise
766 // a program would be required to add an item with wxID_EXIT in order to get the
767 // Quit menu item to be enabled, which seems a bit burdensome.
768 if ( UMAGetSystemVersion() >= 0x1000 && wxApp::s_macExitMenuItemId
)
770 wxMenuItem
*item
= FindItem( wxApp::s_macExitMenuItemId
, NULL
) ;
771 if ( item
!= NULL
&& !(item
->IsEnabled()) )
772 DisableMenuCommand( NULL
, kHICommandQuit
) ;
774 EnableMenuCommand( NULL
, kHICommandQuit
) ;
778 wxString strippedHelpMenuTitle
= wxStripMenuCodes( wxApp::s_macHelpMenuTitleName
) ;
779 wxString strippedTranslatedHelpMenuTitle
= wxStripMenuCodes( wxString( _("&Help") ) ) ;
780 wxMenuList::compatibility_iterator menuIter
= m_menus
.GetFirst();
781 for (size_t i
= 0; i
< m_menus
.GetCount(); i
++, menuIter
= menuIter
->GetNext())
783 wxMenuItemList::compatibility_iterator node
;
785 wxMenu
* menu
= menuIter
->GetData() , *subMenu
= NULL
;
786 wxString strippedMenuTitle
= wxStripMenuCodes(m_titles
[i
]);
788 if ( strippedMenuTitle
== wxT("?") || strippedMenuTitle
== strippedHelpMenuTitle
|| strippedMenuTitle
== strippedTranslatedHelpMenuTitle
)
790 for (node
= menu
->GetMenuItems().GetFirst(); node
; node
= node
->GetNext())
792 item
= (wxMenuItem
*)node
->GetData();
793 subMenu
= item
->GetSubMenu() ;
796 // we don't support hierarchical menus in the help menu yet
800 if ( item
->GetId() != wxApp::s_macAboutMenuItemId
)
802 // we have found a user help menu and an item other than the about item,
803 // so we can create the mac help menu now, if we haven't created it yet
804 if ( helpMenuHandle
== NULL
)
806 if ( UMAGetHelpMenu( &helpMenuHandle
, &firstUserHelpMenuItem
) != noErr
)
808 helpMenuHandle
= NULL
;
814 if ( item
->IsSeparator() )
816 if ( helpMenuHandle
)
817 AppendMenuItemTextWithCFString( helpMenuHandle
,
818 CFSTR(""), kMenuItemAttrSeparator
, 0,NULL
);
823 entry
= wxAcceleratorEntry::Create( item
->GetItemLabel() ) ;
825 if ( item
->GetId() == wxApp::s_macAboutMenuItemId
)
827 // this will be taken care of below
831 if ( helpMenuHandle
)
833 UMAAppendMenuItem(helpMenuHandle
, wxStripMenuCodes(item
->GetItemLabel()) , wxFont::GetDefaultEncoding(), entry
);
834 SetMenuItemCommandID( helpMenuHandle
, CountMenuItems(helpMenuHandle
) , wxIdToMacCommand ( item
->GetId() ) ) ;
835 SetMenuItemRefCon( helpMenuHandle
, CountMenuItems(helpMenuHandle
) , (URefCon
) item
) ;
845 else if ( ( m_titles
[i
] == wxT("Window") || m_titles
[i
] == wxT("&Window") )
846 && GetAutoWindowMenu() )
848 if ( MacGetWindowMenuHMenu() == NULL
)
850 CreateStandardWindowMenu( 0 , (MenuHandle
*) &s_macWindowMenuHandle
) ;
853 MenuRef wm
= (MenuRef
)MacGetWindowMenuHMenu();
857 // get the insertion point in the standard menu
858 MenuItemIndex winListStart
;
859 GetIndMenuItemWithCommandID(wm
,
860 kHICommandWindowListSeparator
, 1, NULL
, &winListStart
);
862 // add a separator so that the standard items and the custom items
863 // aren't mixed together, but only if this is the first run
864 OSStatus err
= GetIndMenuItemWithCommandID(wm
,
865 'WXWM', 1, NULL
, NULL
);
867 if ( err
== menuItemNotFoundErr
)
869 InsertMenuItemTextWithCFString( wm
,
870 CFSTR(""), winListStart
-1, kMenuItemAttrSeparator
, 'WXWM');
873 wxInsertMenuItemsInMenu(menu
, wm
, winListStart
);
877 UMASetMenuTitle( MAC_WXHMENU(menu
->GetHMenu()) , m_titles
[i
], m_font
.GetEncoding() ) ;
878 menu
->MacBeforeDisplay(false) ;
880 ::InsertMenu(MAC_WXHMENU(_wxMenuAt(m_menus
, i
)->GetHMenu()), 0);
884 // take care of the about menu item wherever it is
887 wxMenuItem
*aboutMenuItem
= FindItem(wxApp::s_macAboutMenuItemId
, &aboutMenu
) ;
891 entry
= wxAcceleratorEntry::Create( aboutMenuItem
->GetItemLabel() ) ;
892 UMASetMenuItemText( GetMenuHandle( kwxMacAppleMenuId
) , 1 , wxStripMenuCodes ( aboutMenuItem
->GetItemLabel() ) , wxFont::GetDefaultEncoding() );
893 UMAEnableMenuItem( GetMenuHandle( kwxMacAppleMenuId
) , 1 , true );
894 SetMenuItemCommandID( GetMenuHandle( kwxMacAppleMenuId
) , 1 , kHICommandAbout
) ;
895 SetMenuItemRefCon(GetMenuHandle( kwxMacAppleMenuId
) , 1 , (URefCon
)aboutMenuItem
) ;
896 UMASetMenuItemShortcut( GetMenuHandle( kwxMacAppleMenuId
) , 1 , entry
) ;
900 if ( GetAutoWindowMenu() )
902 if ( MacGetWindowMenuHMenu() == NULL
)
903 CreateStandardWindowMenu( 0 , (MenuHandle
*) &s_macWindowMenuHandle
) ;
905 InsertMenu( (MenuHandle
) MacGetWindowMenuHMenu() , 0 ) ;
909 s_macInstalledMenuBar
= this;
912 void wxMenuBar::EnableTop(size_t pos
, bool enable
)
914 wxCHECK_RET( IsAttached(), wxT("doesn't work with unattached menubars") );
916 _wxMenuAt(m_menus
, pos
)->MacEnableMenu( enable
) ;
920 bool wxMenuBar::Enable(bool enable
)
922 wxCHECK_MSG( IsAttached(), false, wxT("doesn't work with unattached menubars") );
925 for (i
= 0; i
< GetMenuCount(); i
++)
926 EnableTop(i
, enable
);
931 void wxMenuBar::SetMenuLabel(size_t pos
, const wxString
& label
)
933 wxCHECK_RET( pos
< GetMenuCount(), wxT("invalid menu index") );
935 m_titles
[pos
] = label
;
940 _wxMenuAt(m_menus
, pos
)->SetTitle( label
) ;
942 if (wxMenuBar::s_macInstalledMenuBar
== this) // are we currently installed ?
944 ::SetMenuBar( GetMenuBar() ) ;
949 wxString
wxMenuBar::GetMenuLabel(size_t pos
) const
951 wxCHECK_MSG( pos
< GetMenuCount(), wxEmptyString
,
952 wxT("invalid menu index in wxMenuBar::GetMenuLabel") );
954 return m_titles
[pos
];
957 int wxMenuBar::FindMenu(const wxString
& title
)
959 wxString menuTitle
= wxStripMenuCodes(title
);
961 size_t count
= GetMenuCount();
962 for ( size_t i
= 0; i
< count
; i
++ )
964 wxString title
= wxStripMenuCodes(m_titles
[i
]);
965 if ( menuTitle
== title
)
972 // ---------------------------------------------------------------------------
973 // wxMenuBar construction
974 // ---------------------------------------------------------------------------
976 wxMenu
*wxMenuBar::Replace(size_t pos
, wxMenu
*menu
, const wxString
& title
)
978 wxMenu
*menuOld
= wxMenuBarBase::Replace(pos
, menu
, title
);
982 m_titles
[pos
] = title
;
986 if (s_macInstalledMenuBar
== this)
988 menuOld
->MacAfterDisplay( false ) ;
989 ::DeleteMenu( menuOld
->MacGetMenuId() /* m_menus[pos]->MacGetMenuId() */ ) ;
991 menu
->MacBeforeDisplay( false ) ;
992 UMASetMenuTitle( MAC_WXHMENU(menu
->GetHMenu()) , title
, m_font
.GetEncoding() ) ;
993 if ( pos
== m_menus
.GetCount() - 1)
994 ::InsertMenu( MAC_WXHMENU(menu
->GetHMenu()) , 0 ) ;
996 ::InsertMenu( MAC_WXHMENU(menu
->GetHMenu()) , _wxMenuAt(m_menus
, pos
+ 1)->MacGetMenuId() ) ;
1002 if (m_invokingWindow
)
1003 wxMenubarSetInvokingWindow( menu
, m_invokingWindow
);
1008 bool wxMenuBar::Insert(size_t pos
, wxMenu
*menu
, const wxString
& title
)
1010 if ( !wxMenuBarBase::Insert(pos
, menu
, title
) )
1013 m_titles
.Insert(title
, pos
);
1015 UMASetMenuTitle( MAC_WXHMENU(menu
->GetHMenu()) , title
, m_font
.GetEncoding() ) ;
1017 if ( IsAttached() && s_macInstalledMenuBar
== this )
1019 if (s_macInstalledMenuBar
== this)
1021 menu
->MacBeforeDisplay( false ) ;
1023 if ( pos
== (size_t) -1 || pos
+ 1 == m_menus
.GetCount() )
1024 ::InsertMenu( MAC_WXHMENU(menu
->GetHMenu()) , 0 ) ;
1026 ::InsertMenu( MAC_WXHMENU(menu
->GetHMenu()) , _wxMenuAt(m_menus
, pos
+1)->MacGetMenuId() ) ;
1032 if (m_invokingWindow
)
1033 wxMenubarSetInvokingWindow( menu
, m_invokingWindow
);
1038 wxMenu
*wxMenuBar::Remove(size_t pos
)
1040 wxMenu
*menu
= wxMenuBarBase::Remove(pos
);
1046 if (s_macInstalledMenuBar
== this)
1047 ::DeleteMenu( menu
->MacGetMenuId() /* m_menus[pos]->MacGetMenuId() */ ) ;
1052 m_titles
.RemoveAt(pos
);
1057 bool wxMenuBar::Append(wxMenu
*menu
, const wxString
& title
)
1059 WXHMENU submenu
= menu
? menu
->GetHMenu() : 0;
1060 wxCHECK_MSG( submenu
, false, wxT("can't append invalid menu to menubar") );
1062 if ( !wxMenuBarBase::Append(menu
, title
) )
1065 m_titles
.Add(title
);
1067 UMASetMenuTitle( MAC_WXHMENU(menu
->GetHMenu()) , title
, m_font
.GetEncoding() ) ;
1071 if (s_macInstalledMenuBar
== this)
1073 menu
->MacBeforeDisplay( false ) ;
1074 ::InsertMenu( MAC_WXHMENU(menu
->GetHMenu()) , 0 ) ;
1080 // m_invokingWindow is set after wxFrame::SetMenuBar(). This call enables
1081 // adding menu later on.
1082 if (m_invokingWindow
)
1083 wxMenubarSetInvokingWindow( menu
, m_invokingWindow
);
1088 static void wxMenubarUnsetInvokingWindow( wxMenu
*menu
)
1090 menu
->SetInvokingWindow( (wxWindow
*) NULL
);
1091 wxMenuItemList::compatibility_iterator node
= menu
->GetMenuItems().GetFirst();
1095 wxMenuItem
*menuitem
= node
->GetData();
1096 if (menuitem
->IsSubMenu())
1097 wxMenubarUnsetInvokingWindow( menuitem
->GetSubMenu() );
1099 node
= node
->GetNext();
1103 static void wxMenubarSetInvokingWindow( wxMenu
*menu
, wxWindow
*win
)
1105 menu
->SetInvokingWindow( win
);
1106 wxMenuItem
*menuitem
;
1107 wxMenuItemList::compatibility_iterator node
= menu
->GetMenuItems().GetFirst();
1111 menuitem
= node
->GetData();
1112 if (menuitem
->IsSubMenu())
1113 wxMenubarSetInvokingWindow( menuitem
->GetSubMenu() , win
);
1115 node
= node
->GetNext();
1119 void wxMenuBar::UnsetInvokingWindow()
1121 m_invokingWindow
= (wxWindow
*) NULL
;
1123 wxMenuList::compatibility_iterator node
= m_menus
.GetFirst();
1127 menu
= node
->GetData();
1128 wxMenubarUnsetInvokingWindow( menu
);
1130 node
= node
->GetNext();
1134 void wxMenuBar::SetInvokingWindow(wxFrame
*frame
)
1136 m_invokingWindow
= frame
;
1138 wxMenuList::compatibility_iterator node
= m_menus
.GetFirst();
1142 menu
= node
->GetData();
1143 wxMenubarSetInvokingWindow( menu
, frame
);
1145 node
= node
->GetNext();
1149 void wxMenuBar::Detach()
1151 wxMenuBarBase::Detach() ;
1154 void wxMenuBar::Attach(wxFrame
*frame
)
1156 wxMenuBarBase::Attach( frame
) ;
1159 // ---------------------------------------------------------------------------
1160 // wxMenuBar searching for menu items
1161 // ---------------------------------------------------------------------------
1163 // Find the itemString in menuString, and return the item id or wxNOT_FOUND
1164 int wxMenuBar::FindMenuItem(const wxString
& menuString
,
1165 const wxString
& itemString
) const
1167 wxString menuLabel
= wxStripMenuCodes(menuString
);
1168 size_t count
= GetMenuCount();
1169 for ( size_t i
= 0; i
< count
; i
++ )
1171 wxString title
= wxStripMenuCodes(m_titles
[i
]);
1172 if ( menuLabel
== title
)
1173 return _wxMenuAt(m_menus
, i
)->FindItem(itemString
);
1179 wxMenuItem
*wxMenuBar::FindItem(int id
, wxMenu
**itemMenu
) const
1184 wxMenuItem
*item
= NULL
;
1185 size_t count
= GetMenuCount();
1186 for ( size_t i
= 0; !item
&& (i
< count
); i
++ )
1187 item
= _wxMenuAt(m_menus
, i
)->FindItem(id
, itemMenu
);