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 menubar
= NewHandleClear( 6 /* sizeof( MenuBarHeader ) */ ) ;
716 ::SetMenuBar( menubar
) ;
717 DisposeMenuBar( menubar
) ;
718 MenuHandle appleMenu
= NULL
;
720 verify_noerr( CreateNewMenu( kwxMacAppleMenuId
, 0 , &appleMenu
) ) ;
721 verify_noerr( SetMenuTitleWithCFString( appleMenu
, CFSTR( "\x14" ) ) );
723 // Add About/Preferences separator only on OS X
724 // KH/RN: Separator is always present on 10.3 but not on 10.2
725 // However, the change from 10.2 to 10.3 suggests it is preferred
726 InsertMenuItemTextWithCFString( appleMenu
,
727 CFSTR(""), 0, kMenuItemAttrSeparator
, 0);
728 InsertMenuItemTextWithCFString( appleMenu
,
729 CFSTR("About..."), 0, 0, 0);
730 MacInsertMenu( appleMenu
, 0 ) ;
732 // if we have a mac help menu, clean it up before adding new items
733 MenuHandle helpMenuHandle
;
734 MenuItemIndex firstUserHelpMenuItem
;
736 if ( UMAGetHelpMenuDontCreate( &helpMenuHandle
, &firstUserHelpMenuItem
) == noErr
)
738 for ( int i
= CountMenuItems( helpMenuHandle
) ; i
>= firstUserHelpMenuItem
; --i
)
739 DeleteMenuItem( helpMenuHandle
, i
) ;
743 helpMenuHandle
= NULL
;
746 if ( wxApp::s_macPreferencesMenuItemId
)
748 wxMenuItem
*item
= FindItem( wxApp::s_macPreferencesMenuItemId
, NULL
) ;
749 if ( item
== NULL
|| !(item
->IsEnabled()) )
750 DisableMenuCommand( NULL
, kHICommandPreferences
) ;
752 EnableMenuCommand( NULL
, kHICommandPreferences
) ;
755 // Unlike preferences which may or may not exist, the Quit item should be always
756 // enabled unless it is added by the application and then disabled, otherwise
757 // a program would be required to add an item with wxID_EXIT in order to get the
758 // Quit menu item to be enabled, which seems a bit burdensome.
759 if ( wxApp::s_macExitMenuItemId
)
761 wxMenuItem
*item
= FindItem( wxApp::s_macExitMenuItemId
, NULL
) ;
762 if ( item
!= NULL
&& !(item
->IsEnabled()) )
763 DisableMenuCommand( NULL
, kHICommandQuit
) ;
765 EnableMenuCommand( NULL
, kHICommandQuit
) ;
768 wxString strippedHelpMenuTitle
= wxStripMenuCodes( wxApp::s_macHelpMenuTitleName
) ;
769 wxString strippedTranslatedHelpMenuTitle
= wxStripMenuCodes( wxString( _("&Help") ) ) ;
770 wxMenuList::compatibility_iterator menuIter
= m_menus
.GetFirst();
771 for (size_t i
= 0; i
< m_menus
.GetCount(); i
++, menuIter
= menuIter
->GetNext())
773 wxMenuItemList::compatibility_iterator node
;
775 wxMenu
* menu
= menuIter
->GetData() , *subMenu
= NULL
;
776 wxString strippedMenuTitle
= wxStripMenuCodes(m_titles
[i
]);
778 if ( strippedMenuTitle
== wxT("?") || strippedMenuTitle
== strippedHelpMenuTitle
|| strippedMenuTitle
== strippedTranslatedHelpMenuTitle
)
780 for (node
= menu
->GetMenuItems().GetFirst(); node
; node
= node
->GetNext())
782 item
= (wxMenuItem
*)node
->GetData();
783 subMenu
= item
->GetSubMenu() ;
786 // we don't support hierarchical menus in the help menu yet
790 if ( item
->GetId() != wxApp::s_macAboutMenuItemId
)
792 // we have found a user help menu and an item other than the about item,
793 // so we can create the mac help menu now, if we haven't created it yet
794 if ( helpMenuHandle
== NULL
)
796 if ( UMAGetHelpMenu( &helpMenuHandle
, &firstUserHelpMenuItem
) != noErr
)
798 helpMenuHandle
= NULL
;
804 if ( item
->IsSeparator() )
806 if ( helpMenuHandle
)
807 AppendMenuItemTextWithCFString( helpMenuHandle
,
808 CFSTR(""), kMenuItemAttrSeparator
, 0,NULL
);
813 entry
= wxAcceleratorEntry::Create( item
->GetItemLabel() ) ;
815 if ( item
->GetId() == wxApp::s_macAboutMenuItemId
)
817 // this will be taken care of below
821 if ( helpMenuHandle
)
823 UMAAppendMenuItem(helpMenuHandle
, wxStripMenuCodes(item
->GetItemLabel()) , wxFont::GetDefaultEncoding(), entry
);
824 SetMenuItemCommandID( helpMenuHandle
, CountMenuItems(helpMenuHandle
) , wxIdToMacCommand ( item
->GetId() ) ) ;
825 SetMenuItemRefCon( helpMenuHandle
, CountMenuItems(helpMenuHandle
) , (URefCon
) item
) ;
835 else if ( ( m_titles
[i
] == wxT("Window") || m_titles
[i
] == wxT("&Window") )
836 && GetAutoWindowMenu() )
838 if ( MacGetWindowMenuHMenu() == NULL
)
840 CreateStandardWindowMenu( 0 , (MenuHandle
*) &s_macWindowMenuHandle
) ;
843 MenuRef wm
= (MenuRef
)MacGetWindowMenuHMenu();
847 // get the insertion point in the standard menu
848 MenuItemIndex winListStart
;
849 GetIndMenuItemWithCommandID(wm
,
850 kHICommandWindowListSeparator
, 1, NULL
, &winListStart
);
852 // add a separator so that the standard items and the custom items
853 // aren't mixed together, but only if this is the first run
854 OSStatus err
= GetIndMenuItemWithCommandID(wm
,
855 'WXWM', 1, NULL
, NULL
);
857 if ( err
== menuItemNotFoundErr
)
859 InsertMenuItemTextWithCFString( wm
,
860 CFSTR(""), winListStart
-1, kMenuItemAttrSeparator
, 'WXWM');
863 wxInsertMenuItemsInMenu(menu
, wm
, winListStart
);
867 UMASetMenuTitle( MAC_WXHMENU(menu
->GetHMenu()) , m_titles
[i
], m_font
.GetEncoding() ) ;
868 menu
->MacBeforeDisplay(false) ;
870 ::InsertMenu(MAC_WXHMENU(_wxMenuAt(m_menus
, i
)->GetHMenu()), 0);
874 // take care of the about menu item wherever it is
877 wxMenuItem
*aboutMenuItem
= FindItem(wxApp::s_macAboutMenuItemId
, &aboutMenu
) ;
881 entry
= wxAcceleratorEntry::Create( aboutMenuItem
->GetItemLabel() ) ;
882 UMASetMenuItemText( GetMenuHandle( kwxMacAppleMenuId
) , 1 , wxStripMenuCodes ( aboutMenuItem
->GetItemLabel() ) , wxFont::GetDefaultEncoding() );
883 UMAEnableMenuItem( GetMenuHandle( kwxMacAppleMenuId
) , 1 , true );
884 SetMenuItemCommandID( GetMenuHandle( kwxMacAppleMenuId
) , 1 , kHICommandAbout
) ;
885 SetMenuItemRefCon(GetMenuHandle( kwxMacAppleMenuId
) , 1 , (URefCon
)aboutMenuItem
) ;
886 UMASetMenuItemShortcut( GetMenuHandle( kwxMacAppleMenuId
) , 1 , entry
) ;
890 if ( GetAutoWindowMenu() )
892 if ( MacGetWindowMenuHMenu() == NULL
)
893 CreateStandardWindowMenu( 0 , (MenuHandle
*) &s_macWindowMenuHandle
) ;
895 InsertMenu( (MenuHandle
) MacGetWindowMenuHMenu() , 0 ) ;
899 s_macInstalledMenuBar
= this;
902 void wxMenuBar::EnableTop(size_t pos
, bool enable
)
904 wxCHECK_RET( IsAttached(), wxT("doesn't work with unattached menubars") );
906 _wxMenuAt(m_menus
, pos
)->MacEnableMenu( enable
) ;
910 bool wxMenuBar::Enable(bool enable
)
912 wxCHECK_MSG( IsAttached(), false, wxT("doesn't work with unattached menubars") );
915 for (i
= 0; i
< GetMenuCount(); i
++)
916 EnableTop(i
, enable
);
921 void wxMenuBar::SetMenuLabel(size_t pos
, const wxString
& label
)
923 wxCHECK_RET( pos
< GetMenuCount(), wxT("invalid menu index") );
925 m_titles
[pos
] = label
;
930 _wxMenuAt(m_menus
, pos
)->SetTitle( label
) ;
932 if (wxMenuBar::s_macInstalledMenuBar
== this) // are we currently installed ?
934 ::SetMenuBar( GetMenuBar() ) ;
939 wxString
wxMenuBar::GetMenuLabel(size_t pos
) const
941 wxCHECK_MSG( pos
< GetMenuCount(), wxEmptyString
,
942 wxT("invalid menu index in wxMenuBar::GetMenuLabel") );
944 return m_titles
[pos
];
947 int wxMenuBar::FindMenu(const wxString
& title
)
949 wxString menuTitle
= wxStripMenuCodes(title
);
951 size_t count
= GetMenuCount();
952 for ( size_t i
= 0; i
< count
; i
++ )
954 wxString title
= wxStripMenuCodes(m_titles
[i
]);
955 if ( menuTitle
== title
)
962 // ---------------------------------------------------------------------------
963 // wxMenuBar construction
964 // ---------------------------------------------------------------------------
966 wxMenu
*wxMenuBar::Replace(size_t pos
, wxMenu
*menu
, const wxString
& title
)
968 wxMenu
*menuOld
= wxMenuBarBase::Replace(pos
, menu
, title
);
972 m_titles
[pos
] = title
;
976 if (s_macInstalledMenuBar
== this)
978 menuOld
->MacAfterDisplay( false ) ;
979 ::DeleteMenu( menuOld
->MacGetMenuId() /* m_menus[pos]->MacGetMenuId() */ ) ;
981 menu
->MacBeforeDisplay( false ) ;
982 UMASetMenuTitle( MAC_WXHMENU(menu
->GetHMenu()) , title
, m_font
.GetEncoding() ) ;
983 if ( pos
== m_menus
.GetCount() - 1)
984 ::InsertMenu( MAC_WXHMENU(menu
->GetHMenu()) , 0 ) ;
986 ::InsertMenu( MAC_WXHMENU(menu
->GetHMenu()) , _wxMenuAt(m_menus
, pos
+ 1)->MacGetMenuId() ) ;
992 if (m_invokingWindow
)
993 wxMenubarSetInvokingWindow( menu
, m_invokingWindow
);
998 bool wxMenuBar::Insert(size_t pos
, wxMenu
*menu
, const wxString
& title
)
1000 if ( !wxMenuBarBase::Insert(pos
, menu
, title
) )
1003 m_titles
.Insert(title
, pos
);
1005 UMASetMenuTitle( MAC_WXHMENU(menu
->GetHMenu()) , title
, m_font
.GetEncoding() ) ;
1007 if ( IsAttached() && s_macInstalledMenuBar
== this )
1009 if (s_macInstalledMenuBar
== this)
1011 menu
->MacBeforeDisplay( false ) ;
1013 if ( pos
== (size_t) -1 || pos
+ 1 == m_menus
.GetCount() )
1014 ::InsertMenu( MAC_WXHMENU(menu
->GetHMenu()) , 0 ) ;
1016 ::InsertMenu( MAC_WXHMENU(menu
->GetHMenu()) , _wxMenuAt(m_menus
, pos
+1)->MacGetMenuId() ) ;
1022 if (m_invokingWindow
)
1023 wxMenubarSetInvokingWindow( menu
, m_invokingWindow
);
1028 wxMenu
*wxMenuBar::Remove(size_t pos
)
1030 wxMenu
*menu
= wxMenuBarBase::Remove(pos
);
1036 if (s_macInstalledMenuBar
== this)
1037 ::DeleteMenu( menu
->MacGetMenuId() /* m_menus[pos]->MacGetMenuId() */ ) ;
1042 m_titles
.RemoveAt(pos
);
1047 bool wxMenuBar::Append(wxMenu
*menu
, const wxString
& title
)
1049 WXHMENU submenu
= menu
? menu
->GetHMenu() : 0;
1050 wxCHECK_MSG( submenu
, false, wxT("can't append invalid menu to menubar") );
1052 if ( !wxMenuBarBase::Append(menu
, title
) )
1055 m_titles
.Add(title
);
1057 UMASetMenuTitle( MAC_WXHMENU(menu
->GetHMenu()) , title
, m_font
.GetEncoding() ) ;
1061 if (s_macInstalledMenuBar
== this)
1063 menu
->MacBeforeDisplay( false ) ;
1064 ::InsertMenu( MAC_WXHMENU(menu
->GetHMenu()) , 0 ) ;
1070 // m_invokingWindow is set after wxFrame::SetMenuBar(). This call enables
1071 // adding menu later on.
1072 if (m_invokingWindow
)
1073 wxMenubarSetInvokingWindow( menu
, m_invokingWindow
);
1078 static void wxMenubarUnsetInvokingWindow( wxMenu
*menu
)
1080 menu
->SetInvokingWindow( (wxWindow
*) NULL
);
1081 wxMenuItemList::compatibility_iterator node
= menu
->GetMenuItems().GetFirst();
1085 wxMenuItem
*menuitem
= node
->GetData();
1086 if (menuitem
->IsSubMenu())
1087 wxMenubarUnsetInvokingWindow( menuitem
->GetSubMenu() );
1089 node
= node
->GetNext();
1093 static void wxMenubarSetInvokingWindow( wxMenu
*menu
, wxWindow
*win
)
1095 menu
->SetInvokingWindow( win
);
1096 wxMenuItem
*menuitem
;
1097 wxMenuItemList::compatibility_iterator node
= menu
->GetMenuItems().GetFirst();
1101 menuitem
= node
->GetData();
1102 if (menuitem
->IsSubMenu())
1103 wxMenubarSetInvokingWindow( menuitem
->GetSubMenu() , win
);
1105 node
= node
->GetNext();
1109 void wxMenuBar::UnsetInvokingWindow()
1111 m_invokingWindow
= (wxWindow
*) NULL
;
1113 wxMenuList::compatibility_iterator node
= m_menus
.GetFirst();
1117 menu
= node
->GetData();
1118 wxMenubarUnsetInvokingWindow( menu
);
1120 node
= node
->GetNext();
1124 void wxMenuBar::SetInvokingWindow(wxFrame
*frame
)
1126 m_invokingWindow
= frame
;
1128 wxMenuList::compatibility_iterator node
= m_menus
.GetFirst();
1132 menu
= node
->GetData();
1133 wxMenubarSetInvokingWindow( menu
, frame
);
1135 node
= node
->GetNext();
1139 void wxMenuBar::Detach()
1141 wxMenuBarBase::Detach() ;
1144 void wxMenuBar::Attach(wxFrame
*frame
)
1146 wxMenuBarBase::Attach( frame
) ;
1149 // ---------------------------------------------------------------------------
1150 // wxMenuBar searching for menu items
1151 // ---------------------------------------------------------------------------
1153 // Find the itemString in menuString, and return the item id or wxNOT_FOUND
1154 int wxMenuBar::FindMenuItem(const wxString
& menuString
,
1155 const wxString
& itemString
) const
1157 wxString menuLabel
= wxStripMenuCodes(menuString
);
1158 size_t count
= GetMenuCount();
1159 for ( size_t i
= 0; i
< count
; i
++ )
1161 wxString title
= wxStripMenuCodes(m_titles
[i
]);
1162 if ( menuLabel
== title
)
1163 return _wxMenuAt(m_menus
, i
)->FindItem(itemString
);
1169 wxMenuItem
*wxMenuBar::FindItem(int id
, wxMenu
**itemMenu
) const
1174 wxMenuItem
*item
= NULL
;
1175 size_t count
= GetMenuCount();
1176 for ( size_t i
= 0; !item
&& (i
< count
); i
++ )
1177 item
= _wxMenuAt(m_menus
, i
)->FindItem(id
, itemMenu
);