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/osx/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 // We need the !GetMenuBar() check to make sure we run MacBeforeDisplay()
227 // for popup menus and other menus which may not be part of the main
229 if (!GetMenuBar() || wxMenuBar::MacGetInstalledMenuBar() == GetMenuBar())
230 pSubMenu
->MacBeforeDisplay( true ) ;
232 if ( pos
== (size_t)-1 )
233 UMAAppendSubMenuItem(MAC_WXHMENU(m_hMenu
), wxStripMenuCodes(pItem
->GetItemLabel()), wxFont::GetDefaultEncoding(), pSubMenu
->m_macMenuId
);
235 UMAInsertSubMenuItem(MAC_WXHMENU(m_hMenu
), wxStripMenuCodes(pItem
->GetItemLabel()), wxFont::GetDefaultEncoding(), pos
, pSubMenu
->m_macMenuId
);
237 pItem
->UpdateItemBitmap() ;
238 pItem
->UpdateItemStatus() ;
242 if ( pos
== (size_t)-1 )
244 UMAAppendMenuItem(MAC_WXHMENU(m_hMenu
), wxT("a") , wxFont::GetDefaultEncoding() );
245 pos
= CountMenuItems(MAC_WXHMENU(m_hMenu
)) ;
249 // MacOS counts menu items from 1 and inserts after, therefore having the
250 // same effect as wx 0 based and inserting before, we must correct pos
251 // after however for updates to be correct
252 UMAInsertMenuItem(MAC_WXHMENU(m_hMenu
), wxT("a"), wxFont::GetDefaultEncoding(), pos
);
256 SetMenuItemCommandID( MAC_WXHMENU(m_hMenu
) , pos
, wxIdToMacCommand ( pItem
->GetId() ) ) ;
257 SetMenuItemRefCon( MAC_WXHMENU(m_hMenu
) , pos
, (URefCon
) pItem
) ;
258 pItem
->UpdateItemText() ;
259 pItem
->UpdateItemBitmap() ;
260 pItem
->UpdateItemStatus() ;
262 if ( pItem
->GetId() == idMenuTitle
)
263 UMAEnableMenuItem(MAC_WXHMENU(m_hMenu
) , pos
, false ) ;
267 // if we're already attached to the menubar, we must update it
268 if ( IsAttached() && GetMenuBar()->IsAttached() )
269 GetMenuBar()->Refresh();
274 void wxMenu::EndRadioGroup()
276 // we're not inside a radio group any longer
277 m_startRadioGroup
= -1;
280 wxMenuItem
* wxMenu::DoAppend(wxMenuItem
*item
)
282 wxCHECK_MSG( item
, NULL
, _T("NULL item in wxMenu::DoAppend") );
286 if ( item
->GetKind() == wxITEM_RADIO
)
288 int count
= GetMenuItemCount();
290 if ( m_startRadioGroup
== -1 )
292 // start a new radio group
293 m_startRadioGroup
= count
;
295 // for now it has just one element
296 item
->SetAsRadioGroupStart();
297 item
->SetRadioGroupEnd(m_startRadioGroup
);
299 // ensure that we have a checked item in the radio group
302 else // extend the current radio group
304 // we need to update its end item
305 item
->SetRadioGroupStart(m_startRadioGroup
);
306 wxMenuItemList::compatibility_iterator node
= GetMenuItems().Item(m_startRadioGroup
);
310 node
->GetData()->SetRadioGroupEnd(count
);
314 wxFAIL_MSG( _T("where is the radio group start item?") );
318 else // not a radio item
323 if ( !wxMenuBase::DoAppend(item
) || !DoInsertOrAppend(item
) )
327 // check the item initially
333 wxMenuItem
* wxMenu::DoInsert(size_t pos
, wxMenuItem
*item
)
335 if (wxMenuBase::DoInsert(pos
, item
) && DoInsertOrAppend(item
, pos
))
341 wxMenuItem
*wxMenu::DoRemove(wxMenuItem
*item
)
343 // we need to find the items position in the child list
345 wxMenuItemList::compatibility_iterator node
= GetMenuItems().GetFirst();
347 for ( pos
= 0; node
; pos
++ )
349 if ( node
->GetData() == item
)
352 node
= node
->GetNext();
355 // DoRemove() (unlike Remove) can only be called for existing item!
356 wxCHECK_MSG( node
, NULL
, wxT("bug in wxMenu::Remove logic") );
358 ::DeleteMenuItem(MAC_WXHMENU(m_hMenu
) , pos
+ 1);
360 if ( IsAttached() && GetMenuBar()->IsAttached() )
361 // otherwise, the change won't be visible
362 GetMenuBar()->Refresh();
364 // and from internal data structures
365 return wxMenuBase::DoRemove(item
);
368 void wxMenu::SetTitle(const wxString
& label
)
371 UMASetMenuTitle(MAC_WXHMENU(m_hMenu
) , label
, wxFont::GetDefaultEncoding() ) ;
374 bool wxMenu::ProcessCommand(wxCommandEvent
& event
)
376 bool processed
= false;
378 // Try the menu's event handler
379 if ( /* !processed && */ GetEventHandler())
380 processed
= GetEventHandler()->SafelyProcessEvent(event
);
382 // Try the window the menu was popped up from
383 // (and up through the hierarchy)
384 wxWindow
*win
= GetInvokingWindow();
385 if ( !processed
&& win
)
386 processed
= win
->HandleWindowEvent(event
);
391 // ---------------------------------------------------------------------------
393 // ---------------------------------------------------------------------------
395 wxWindow
*wxMenu::GetWindow() const
397 if ( m_invokingWindow
!= NULL
)
398 return m_invokingWindow
;
399 else if ( GetMenuBar() != NULL
)
400 return (wxWindow
*) GetMenuBar()->GetFrame();
405 // helper functions returning the mac menu position for a certain item, note that this is
406 // mac-wise 1 - based, i.e. the first item has index 1 whereas on MSWin it has pos 0
408 int wxMenu::MacGetIndexFromId( int id
)
411 wxMenuItemList::compatibility_iterator node
= GetMenuItems().GetFirst();
412 for ( pos
= 0; node
; pos
++ )
414 if ( node
->GetData()->GetId() == id
)
417 node
= node
->GetNext();
426 int wxMenu::MacGetIndexFromItem( wxMenuItem
*pItem
)
429 wxMenuItemList::compatibility_iterator node
= GetMenuItems().GetFirst();
430 for ( pos
= 0; node
; pos
++ )
432 if ( node
->GetData() == pItem
)
435 node
= node
->GetNext();
444 void wxMenu::MacEnableMenu( bool bDoEnable
)
446 UMAEnableMenuItem(MAC_WXHMENU(m_hMenu
) , 0 , bDoEnable
) ;
451 // MacOS needs to know about submenus somewhere within this menu
452 // before it can be displayed, also hide special menu items
453 // like preferences that are handled by the OS
454 void wxMenu::MacBeforeDisplay( bool isSubMenu
)
456 wxMenuItem
* previousItem
= NULL
;
458 wxMenuItemList::compatibility_iterator node
;
461 for (pos
= 0, node
= GetMenuItems().GetFirst(); node
; node
= node
->GetNext(), pos
++)
463 item
= (wxMenuItem
*)node
->GetData();
464 wxMenu
* subMenu
= item
->GetSubMenu() ;
467 subMenu
->MacBeforeDisplay( true ) ;
471 // what we do here is to hide the special items which are
472 // shown in the application menu anyhow -- it doesn't make
473 // sense to show them in their normal place as well
474 if ( item
->GetId() == wxApp::s_macAboutMenuItemId
||
475 item
->GetId() == wxApp::s_macPreferencesMenuItemId
||
476 item
->GetId() == wxApp::s_macExitMenuItemId
)
479 ChangeMenuItemAttributes( MAC_WXHMENU( GetHMenu() ),
480 pos
+ 1, kMenuItemAttrHidden
, 0 );
482 // also check for a separator which was used just to
483 // separate this item from the others, so don't leave
484 // separator at the menu start or end nor 2 consecutive
486 wxMenuItemList::compatibility_iterator nextNode
= node
->GetNext();
487 wxMenuItem
*next
= nextNode
? nextNode
->GetData() : NULL
;
490 if ( !previousItem
&& next
&& next
->IsSeparator() )
492 // next (i.e. second as we must be first) item is
493 // the separator to hide
494 wxASSERT_MSG( pos
== 0, _T("should be the menu start") );
497 else if ( GetMenuItems().GetCount() == pos
+ 1 &&
498 previousItem
!= NULL
&&
499 previousItem
->IsSeparator() )
501 // prev item is a trailing separator we want to hide
504 else if ( previousItem
&& previousItem
->IsSeparator() &&
505 next
&& next
->IsSeparator() )
507 // two consecutive separators, this is one too many
510 else // no separators to hide
517 // hide the separator as well
518 ChangeMenuItemAttributes( MAC_WXHMENU( GetHMenu() ),
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
->HandleWindowEvent(event
) )
580 wxInt32
wxMenu::MacHandleCommandUpdateStatus(wxMenuItem
* WXUNUSED(item
),
582 wxWindow
* targetWindow
)
584 OSStatus result
= eventNotHandledErr
;
585 wxUpdateUIEvent
event(id
);
586 event
.SetEventObject( this );
588 bool processed
= false;
590 // Try the menu's event handler
592 wxEvtHandler
*handler
= GetEventHandler();
594 processed
= handler
->ProcessEvent(event
);
597 // Try the window the menu was popped up from
598 // (and up through the hierarchy)
601 const wxMenuBase
*menu
= this;
604 wxWindow
*win
= menu
->GetInvokingWindow();
607 processed
= win
->HandleWindowEvent(event
);
611 menu
= menu
->GetParent();
615 if ( !processed
&& targetWindow
!= NULL
)
617 processed
= targetWindow
->HandleWindowEvent(event
);
622 // if anything changed, update the changed attribute
623 if (event
.GetSetText())
624 SetLabel(id
, event
.GetText());
625 if (event
.GetSetChecked())
626 Check(id
, event
.GetChecked());
627 if (event
.GetSetEnabled())
628 Enable(id
, event
.GetEnabled());
639 Mac Implementation note :
641 The Mac has only one global menubar, so we attempt to install the currently
642 active menubar from a frame, we currently don't take into account mdi-frames
643 which would ask for menu-merging
645 Secondly there is no mac api for changing a menubar that is not the current
646 menubar, so we have to wait for preparing the actual menubar until the
647 wxMenubar is to be used
649 We can in subsequent versions use MacInstallMenuBar to provide some sort of
650 auto-merge for MDI in case this will be necessary
654 wxMenuBar
* wxMenuBar::s_macInstalledMenuBar
= NULL
;
655 wxMenuBar
* wxMenuBar::s_macCommonMenuBar
= NULL
;
656 bool wxMenuBar::s_macAutoWindowMenu
= true ;
657 WXHMENU
wxMenuBar::s_macWindowMenuHandle
= NULL
;
659 void wxMenuBar::Init()
661 m_eventHandler
= this;
662 m_menuBarFrame
= NULL
;
663 m_invokingWindow
= (wxWindow
*) NULL
;
666 wxMenuBar::wxMenuBar()
671 wxMenuBar::wxMenuBar( long WXUNUSED(style
) )
676 wxMenuBar::wxMenuBar(size_t count
, wxMenu
*menus
[], const wxString titles
[], long WXUNUSED(style
))
680 m_titles
.Alloc(count
);
682 for ( size_t i
= 0; i
< count
; i
++ )
684 m_menus
.Append(menus
[i
]);
685 m_titles
.Add(titles
[i
]);
687 menus
[i
]->Attach(this);
691 wxMenuBar::~wxMenuBar()
693 if (s_macCommonMenuBar
== this)
694 s_macCommonMenuBar
= NULL
;
696 if (s_macInstalledMenuBar
== this)
699 s_macInstalledMenuBar
= NULL
;
703 void wxMenuBar::Refresh(bool WXUNUSED(eraseBackground
), const wxRect
*WXUNUSED(rect
))
705 wxCHECK_RET( IsAttached(), wxT("can't refresh unatteched menubar") );
710 void wxMenuBar::MacInstallMenuBar()
712 if ( s_macInstalledMenuBar
== this )
715 MenuBarHandle menubar
= NULL
;
717 menubar
= NewHandleClear( 6 /* sizeof( MenuBarHeader ) */ ) ;
719 ::SetMenuBar( menubar
) ;
720 DisposeMenuBar( menubar
) ;
721 MenuHandle appleMenu
= NULL
;
723 verify_noerr( CreateNewMenu( kwxMacAppleMenuId
, 0 , &appleMenu
) ) ;
724 verify_noerr( SetMenuTitleWithCFString( appleMenu
, CFSTR( "\x14" ) ) );
726 // Add About/Preferences separator only on OS X
727 // KH/RN: Separator is always present on 10.3 but not on 10.2
728 // However, the change from 10.2 to 10.3 suggests it is preferred
729 InsertMenuItemTextWithCFString( appleMenu
,
730 CFSTR(""), 0, kMenuItemAttrSeparator
, 0);
731 InsertMenuItemTextWithCFString( appleMenu
,
732 CFSTR("About..."), 0, 0, 0);
733 MacInsertMenu( appleMenu
, 0 ) ;
735 // if we have a mac help menu, clean it up before adding new items
736 MenuHandle helpMenuHandle
;
737 MenuItemIndex firstUserHelpMenuItem
;
739 if ( UMAGetHelpMenuDontCreate( &helpMenuHandle
, &firstUserHelpMenuItem
) == noErr
)
741 for ( int i
= CountMenuItems( helpMenuHandle
) ; i
>= firstUserHelpMenuItem
; --i
)
742 DeleteMenuItem( helpMenuHandle
, i
) ;
746 helpMenuHandle
= NULL
;
749 if ( wxApp::s_macPreferencesMenuItemId
)
751 wxMenuItem
*item
= FindItem( wxApp::s_macPreferencesMenuItemId
, NULL
) ;
752 if ( item
== NULL
|| !(item
->IsEnabled()) )
753 DisableMenuCommand( NULL
, kHICommandPreferences
) ;
755 EnableMenuCommand( NULL
, kHICommandPreferences
) ;
758 // Unlike preferences which may or may not exist, the Quit item should be always
759 // enabled unless it is added by the application and then disabled, otherwise
760 // a program would be required to add an item with wxID_EXIT in order to get the
761 // Quit menu item to be enabled, which seems a bit burdensome.
762 if ( wxApp::s_macExitMenuItemId
)
764 wxMenuItem
*item
= FindItem( wxApp::s_macExitMenuItemId
, NULL
) ;
765 if ( item
!= NULL
&& !(item
->IsEnabled()) )
766 DisableMenuCommand( NULL
, kHICommandQuit
) ;
768 EnableMenuCommand( NULL
, kHICommandQuit
) ;
771 wxString strippedHelpMenuTitle
= wxStripMenuCodes( wxApp::s_macHelpMenuTitleName
) ;
772 wxString strippedTranslatedHelpMenuTitle
= wxStripMenuCodes( wxString( _("&Help") ) ) ;
773 wxMenuList::compatibility_iterator menuIter
= m_menus
.GetFirst();
774 for (size_t i
= 0; i
< m_menus
.GetCount(); i
++, menuIter
= menuIter
->GetNext())
776 wxMenuItemList::compatibility_iterator node
;
778 wxMenu
* menu
= menuIter
->GetData() , *subMenu
= NULL
;
779 wxString strippedMenuTitle
= wxStripMenuCodes(m_titles
[i
]);
781 if ( strippedMenuTitle
== wxT("?") || strippedMenuTitle
== strippedHelpMenuTitle
|| strippedMenuTitle
== strippedTranslatedHelpMenuTitle
)
783 for (node
= menu
->GetMenuItems().GetFirst(); node
; node
= node
->GetNext())
785 item
= (wxMenuItem
*)node
->GetData();
786 subMenu
= item
->GetSubMenu() ;
789 // we don't support hierarchical menus in the help menu yet
793 if ( item
->GetId() != wxApp::s_macAboutMenuItemId
)
795 // we have found a user help menu and an item other than the about item,
796 // so we can create the mac help menu now, if we haven't created it yet
797 if ( helpMenuHandle
== NULL
)
799 if ( UMAGetHelpMenu( &helpMenuHandle
, &firstUserHelpMenuItem
) != noErr
)
801 helpMenuHandle
= NULL
;
807 if ( item
->IsSeparator() )
809 if ( helpMenuHandle
)
810 AppendMenuItemTextWithCFString( helpMenuHandle
,
811 CFSTR(""), kMenuItemAttrSeparator
, 0,NULL
);
816 entry
= wxAcceleratorEntry::Create( item
->GetItemLabel() ) ;
818 if ( item
->GetId() == wxApp::s_macAboutMenuItemId
)
820 // this will be taken care of below
824 if ( helpMenuHandle
)
826 UMAAppendMenuItem(helpMenuHandle
, wxStripMenuCodes(item
->GetItemLabel()) , wxFont::GetDefaultEncoding(), entry
);
827 SetMenuItemCommandID( helpMenuHandle
, CountMenuItems(helpMenuHandle
) , wxIdToMacCommand ( item
->GetId() ) ) ;
828 SetMenuItemRefCon( helpMenuHandle
, CountMenuItems(helpMenuHandle
) , (URefCon
) item
) ;
838 else if ( ( m_titles
[i
] == wxT("Window") || m_titles
[i
] == wxT("&Window") )
839 && GetAutoWindowMenu() )
841 if ( MacGetWindowMenuHMenu() == NULL
)
843 CreateStandardWindowMenu( 0 , (MenuHandle
*) &s_macWindowMenuHandle
) ;
846 MenuRef wm
= (MenuRef
)MacGetWindowMenuHMenu();
850 // get the insertion point in the standard menu
851 MenuItemIndex winListStart
;
852 GetIndMenuItemWithCommandID(wm
,
853 kHICommandWindowListSeparator
, 1, NULL
, &winListStart
);
855 // add a separator so that the standard items and the custom items
856 // aren't mixed together, but only if this is the first run
857 OSStatus err
= GetIndMenuItemWithCommandID(wm
,
858 'WXWM', 1, NULL
, NULL
);
860 if ( err
== menuItemNotFoundErr
)
862 InsertMenuItemTextWithCFString( wm
,
863 CFSTR(""), winListStart
-1, kMenuItemAttrSeparator
, 'WXWM');
866 wxInsertMenuItemsInMenu(menu
, wm
, winListStart
);
870 UMASetMenuTitle( MAC_WXHMENU(menu
->GetHMenu()) , m_titles
[i
], GetFont().GetEncoding() ) ;
871 menu
->MacBeforeDisplay(false) ;
873 ::InsertMenu(MAC_WXHMENU(_wxMenuAt(m_menus
, i
)->GetHMenu()), 0);
877 // take care of the about menu item wherever it is
880 wxMenuItem
*aboutMenuItem
= FindItem(wxApp::s_macAboutMenuItemId
, &aboutMenu
) ;
884 entry
= wxAcceleratorEntry::Create( aboutMenuItem
->GetItemLabel() ) ;
885 UMASetMenuItemText( GetMenuHandle( kwxMacAppleMenuId
) , 1 , wxStripMenuCodes ( aboutMenuItem
->GetItemLabel() ) , wxFont::GetDefaultEncoding() );
886 UMAEnableMenuItem( GetMenuHandle( kwxMacAppleMenuId
) , 1 , true );
887 SetMenuItemCommandID( GetMenuHandle( kwxMacAppleMenuId
) , 1 , kHICommandAbout
) ;
888 SetMenuItemRefCon(GetMenuHandle( kwxMacAppleMenuId
) , 1 , (URefCon
)aboutMenuItem
) ;
889 UMASetMenuItemShortcut( GetMenuHandle( kwxMacAppleMenuId
) , 1 , entry
) ;
893 if ( GetAutoWindowMenu() )
895 if ( MacGetWindowMenuHMenu() == NULL
)
896 CreateStandardWindowMenu( 0 , (MenuHandle
*) &s_macWindowMenuHandle
) ;
898 InsertMenu( (MenuHandle
) MacGetWindowMenuHMenu() , 0 ) ;
902 s_macInstalledMenuBar
= this;
905 void wxMenuBar::EnableTop(size_t pos
, bool enable
)
907 wxCHECK_RET( IsAttached(), wxT("doesn't work with unattached menubars") );
909 _wxMenuAt(m_menus
, pos
)->MacEnableMenu( enable
) ;
913 bool wxMenuBar::Enable(bool enable
)
915 wxCHECK_MSG( IsAttached(), false, wxT("doesn't work with unattached menubars") );
918 for (i
= 0; i
< GetMenuCount(); i
++)
919 EnableTop(i
, enable
);
924 void wxMenuBar::SetMenuLabel(size_t pos
, const wxString
& label
)
926 wxCHECK_RET( pos
< GetMenuCount(), wxT("invalid menu index") );
928 m_titles
[pos
] = label
;
933 _wxMenuAt(m_menus
, pos
)->SetTitle( label
) ;
935 if (wxMenuBar::s_macInstalledMenuBar
== this) // are we currently installed ?
937 ::SetMenuBar( GetMenuBar() ) ;
942 wxString
wxMenuBar::GetMenuLabel(size_t pos
) const
944 wxCHECK_MSG( pos
< GetMenuCount(), wxEmptyString
,
945 wxT("invalid menu index in wxMenuBar::GetMenuLabel") );
947 return m_titles
[pos
];
950 int wxMenuBar::FindMenu(const wxString
& title
)
952 wxString menuTitle
= wxStripMenuCodes(title
);
954 size_t count
= GetMenuCount();
955 for ( size_t i
= 0; i
< count
; i
++ )
957 wxString title
= wxStripMenuCodes(m_titles
[i
]);
958 if ( menuTitle
== title
)
965 // ---------------------------------------------------------------------------
966 // wxMenuBar construction
967 // ---------------------------------------------------------------------------
969 wxMenu
*wxMenuBar::Replace(size_t pos
, wxMenu
*menu
, const wxString
& title
)
971 wxMenu
*menuOld
= wxMenuBarBase::Replace(pos
, menu
, title
);
975 m_titles
[pos
] = title
;
979 if (s_macInstalledMenuBar
== this)
981 menuOld
->MacAfterDisplay( false ) ;
982 ::DeleteMenu( menuOld
->MacGetMenuId() /* m_menus[pos]->MacGetMenuId() */ ) ;
984 menu
->MacBeforeDisplay( false ) ;
985 UMASetMenuTitle( MAC_WXHMENU(menu
->GetHMenu()) , title
, GetFont().GetEncoding() ) ;
986 if ( pos
== m_menus
.GetCount() - 1)
987 ::InsertMenu( MAC_WXHMENU(menu
->GetHMenu()) , 0 ) ;
989 ::InsertMenu( MAC_WXHMENU(menu
->GetHMenu()) , _wxMenuAt(m_menus
, pos
+ 1)->MacGetMenuId() ) ;
995 if (m_invokingWindow
)
996 wxMenubarSetInvokingWindow( menu
, m_invokingWindow
);
1001 bool wxMenuBar::Insert(size_t pos
, wxMenu
*menu
, const wxString
& title
)
1003 if ( !wxMenuBarBase::Insert(pos
, menu
, title
) )
1006 m_titles
.Insert(title
, pos
);
1008 UMASetMenuTitle( MAC_WXHMENU(menu
->GetHMenu()) , title
, GetFont().GetEncoding() ) ;
1010 if ( IsAttached() && s_macInstalledMenuBar
== this )
1012 if (s_macInstalledMenuBar
== this)
1014 menu
->MacBeforeDisplay( false ) ;
1016 if ( pos
== (size_t) -1 || pos
+ 1 == m_menus
.GetCount() )
1017 ::InsertMenu( MAC_WXHMENU(menu
->GetHMenu()) , 0 ) ;
1019 ::InsertMenu( MAC_WXHMENU(menu
->GetHMenu()) , _wxMenuAt(m_menus
, pos
+1)->MacGetMenuId() ) ;
1025 if (m_invokingWindow
)
1026 wxMenubarSetInvokingWindow( menu
, m_invokingWindow
);
1031 wxMenu
*wxMenuBar::Remove(size_t pos
)
1033 wxMenu
*menu
= wxMenuBarBase::Remove(pos
);
1039 if (s_macInstalledMenuBar
== this)
1040 ::DeleteMenu( menu
->MacGetMenuId() /* m_menus[pos]->MacGetMenuId() */ ) ;
1045 m_titles
.RemoveAt(pos
);
1050 bool wxMenuBar::Append(wxMenu
*menu
, const wxString
& title
)
1052 WXHMENU submenu
= menu
? menu
->GetHMenu() : 0;
1053 wxCHECK_MSG( submenu
, false, wxT("can't append invalid menu to menubar") );
1055 if ( !wxMenuBarBase::Append(menu
, title
) )
1058 m_titles
.Add(title
);
1060 UMASetMenuTitle( MAC_WXHMENU(menu
->GetHMenu()) , title
, GetFont().GetEncoding() ) ;
1064 if (s_macInstalledMenuBar
== this)
1066 menu
->MacBeforeDisplay( false ) ;
1067 ::InsertMenu( MAC_WXHMENU(menu
->GetHMenu()) , 0 ) ;
1073 // m_invokingWindow is set after wxFrame::SetMenuBar(). This call enables
1074 // adding menu later on.
1075 if (m_invokingWindow
)
1076 wxMenubarSetInvokingWindow( menu
, m_invokingWindow
);
1081 static void wxMenubarUnsetInvokingWindow( wxMenu
*menu
)
1083 menu
->SetInvokingWindow( (wxWindow
*) NULL
);
1084 wxMenuItemList::compatibility_iterator node
= menu
->GetMenuItems().GetFirst();
1088 wxMenuItem
*menuitem
= node
->GetData();
1089 if (menuitem
->IsSubMenu())
1090 wxMenubarUnsetInvokingWindow( menuitem
->GetSubMenu() );
1092 node
= node
->GetNext();
1096 static void wxMenubarSetInvokingWindow( wxMenu
*menu
, wxWindow
*win
)
1098 menu
->SetInvokingWindow( win
);
1099 wxMenuItem
*menuitem
;
1100 wxMenuItemList::compatibility_iterator node
= menu
->GetMenuItems().GetFirst();
1104 menuitem
= node
->GetData();
1105 if (menuitem
->IsSubMenu())
1106 wxMenubarSetInvokingWindow( menuitem
->GetSubMenu() , win
);
1108 node
= node
->GetNext();
1112 void wxMenuBar::UnsetInvokingWindow()
1114 m_invokingWindow
= (wxWindow
*) NULL
;
1116 wxMenuList::compatibility_iterator node
= m_menus
.GetFirst();
1120 menu
= node
->GetData();
1121 wxMenubarUnsetInvokingWindow( menu
);
1123 node
= node
->GetNext();
1127 void wxMenuBar::SetInvokingWindow(wxFrame
*frame
)
1129 m_invokingWindow
= frame
;
1131 wxMenuList::compatibility_iterator node
= m_menus
.GetFirst();
1135 menu
= node
->GetData();
1136 wxMenubarSetInvokingWindow( menu
, frame
);
1138 node
= node
->GetNext();
1142 void wxMenuBar::Detach()
1144 wxMenuBarBase::Detach() ;
1147 void wxMenuBar::Attach(wxFrame
*frame
)
1149 wxMenuBarBase::Attach( frame
) ;
1152 // ---------------------------------------------------------------------------
1153 // wxMenuBar searching for menu items
1154 // ---------------------------------------------------------------------------
1156 // Find the itemString in menuString, and return the item id or wxNOT_FOUND
1157 int wxMenuBar::FindMenuItem(const wxString
& menuString
,
1158 const wxString
& itemString
) const
1160 wxString menuLabel
= wxStripMenuCodes(menuString
);
1161 size_t count
= GetMenuCount();
1162 for ( size_t i
= 0; i
< count
; i
++ )
1164 wxString title
= wxStripMenuCodes(m_titles
[i
]);
1165 if ( menuLabel
== title
)
1166 return _wxMenuAt(m_menus
, i
)->FindItem(itemString
);
1172 wxMenuItem
*wxMenuBar::FindItem(int id
, wxMenu
**itemMenu
) const
1177 wxMenuItem
*item
= NULL
;
1178 size_t count
= GetMenuCount();
1179 for ( size_t i
= 0; !item
&& (i
< count
); i
++ )
1180 item
= _wxMenuAt(m_menus
, i
)->FindItem(id
, itemMenu
);