No real changes, just get rid of _wxMenuAt() in wxOSX menu code.
[wxWidgets.git] / src / osx / menu_osx.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/osx/menu_osx.cpp
3 // Purpose: wxMenu, wxMenuBar, wxMenuItem
4 // Author: Stefan Csomor
5 // Modified by:
6 // Created: 1998-01-01
7 // RCS-ID: $Id$
8 // Copyright: (c) Stefan Csomor
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 // ============================================================================
13 // headers & declarations
14 // ============================================================================
15
16 // wxWidgets headers
17 // -----------------
18
19 #include "wx/wxprec.h"
20
21 #if wxUSE_MENUS
22
23 #include "wx/menu.h"
24
25 #ifndef WX_PRECOMP
26 #include "wx/log.h"
27 #include "wx/app.h"
28 #include "wx/utils.h"
29 #include "wx/frame.h"
30 #include "wx/dialog.h"
31 #include "wx/menuitem.h"
32 #endif
33
34 #include "wx/osx/private.h"
35
36 // other standard headers
37 // ----------------------
38 #include <string.h>
39
40 IMPLEMENT_ABSTRACT_CLASS( wxMenuImpl , wxObject )
41
42 wxMenuImpl::~wxMenuImpl()
43 {
44 }
45
46 IMPLEMENT_DYNAMIC_CLASS(wxMenu, wxEvtHandler)
47 IMPLEMENT_DYNAMIC_CLASS(wxMenuBar, wxEvtHandler)
48
49 // the (popup) menu title has this special id
50 static const int idMenuTitle = -3;
51
52 // ============================================================================
53 // implementation
54 // ============================================================================
55
56 // Menus
57
58 // Construct a menu with optional title (then use append)
59
60 void wxMenu::Init()
61 {
62 m_doBreak = false;
63 m_startRadioGroup = -1;
64 m_allowRearrange = true;
65 m_noEventsMode = false;
66
67 m_peer = wxMenuImpl::Create( this, wxStripMenuCodes(m_title) );
68
69
70 // if we have a title, insert it in the beginning of the menu
71 if ( !m_title.empty() )
72 {
73 Append(idMenuTitle, m_title) ;
74 AppendSeparator() ;
75 }
76 }
77
78 wxMenu::~wxMenu()
79 {
80 delete m_peer;
81 }
82
83 WXHMENU wxMenu::GetHMenu() const
84 {
85 if ( m_peer )
86 return m_peer->GetHMenu();
87 return NULL;
88 }
89
90 void wxMenu::Break()
91 {
92 // not available on the mac platform
93 }
94
95 void wxMenu::Attach(wxMenuBarBase *menubar)
96 {
97 wxMenuBase::Attach(menubar);
98
99 EndRadioGroup();
100 }
101
102 void wxMenu::SetAllowRearrange( bool allow )
103 {
104 m_allowRearrange = allow;
105 }
106
107 void wxMenu::SetNoEventsMode( bool noEvents )
108 {
109 m_noEventsMode = noEvents;
110 }
111
112 // function appends a new item or submenu to the menu
113 // append a new item or submenu to the menu
114 bool wxMenu::DoInsertOrAppend(wxMenuItem *pItem, size_t pos)
115 {
116 wxASSERT_MSG( pItem != NULL, wxT("can't append NULL item to the menu") );
117 m_peer->InsertOrAppend( pItem, pos );
118
119 if ( pItem->IsSeparator() )
120 {
121 // nothing to do here
122 }
123 else
124 {
125 wxMenu *pSubMenu = pItem->GetSubMenu() ;
126 if ( pSubMenu != NULL )
127 {
128 wxASSERT_MSG( pSubMenu->GetHMenu() != NULL , wxT("invalid submenu added"));
129 pSubMenu->m_menuParent = this ;
130
131 pSubMenu->DoRearrange();
132 }
133 else
134 {
135 if ( pItem->GetId() == idMenuTitle )
136 pItem->GetMenu()->Enable( idMenuTitle, false );
137 }
138 }
139
140 // if we're already attached to the menubar, we must update it
141 if ( IsAttached() && GetMenuBar()->IsAttached() )
142 GetMenuBar()->Refresh();
143
144 return true ;
145 }
146
147 void wxMenu::EndRadioGroup()
148 {
149 // we're not inside a radio group any longer
150 m_startRadioGroup = -1;
151 }
152
153 wxMenuItem* wxMenu::DoAppend(wxMenuItem *item)
154 {
155 wxCHECK_MSG( item, NULL, wxT("NULL item in wxMenu::DoAppend") );
156
157 bool check = false;
158
159 if ( item->GetKind() == wxITEM_RADIO )
160 {
161 int count = GetMenuItemCount();
162
163 if ( m_startRadioGroup == -1 )
164 {
165 // start a new radio group
166 m_startRadioGroup = count;
167
168 // for now it has just one element
169 item->SetAsRadioGroupStart();
170 item->SetRadioGroupEnd(m_startRadioGroup);
171
172 // ensure that we have a checked item in the radio group
173 check = true;
174 }
175 else // extend the current radio group
176 {
177 // we need to update its end item
178 item->SetRadioGroupStart(m_startRadioGroup);
179 wxMenuItemList::compatibility_iterator node = GetMenuItems().Item(m_startRadioGroup);
180
181 if ( node )
182 {
183 node->GetData()->SetRadioGroupEnd(count);
184 }
185 else
186 {
187 wxFAIL_MSG( wxT("where is the radio group start item?") );
188 }
189 }
190 }
191 else // not a radio item
192 {
193 EndRadioGroup();
194 }
195
196 if ( !wxMenuBase::DoAppend(item) || !DoInsertOrAppend(item) )
197 return NULL;
198
199 if ( check )
200 // check the item initially
201 item->Check(true);
202
203 return item;
204 }
205
206 wxMenuItem* wxMenu::DoInsert(size_t pos, wxMenuItem *item)
207 {
208 if (wxMenuBase::DoInsert(pos, item) && DoInsertOrAppend(item, pos))
209 return item;
210
211 return NULL;
212 }
213
214 wxMenuItem *wxMenu::DoRemove(wxMenuItem *item)
215 {
216 /*
217 // we need to find the items position in the child list
218 size_t pos;
219 wxMenuItemList::compatibility_iterator node = GetMenuItems().GetFirst();
220
221 for ( pos = 0; node; pos++ )
222 {
223 if ( node->GetData() == item )
224 break;
225
226 node = node->GetNext();
227 }
228
229 // DoRemove() (unlike Remove) can only be called for existing item!
230 wxCHECK_MSG( node, NULL, wxT("bug in wxMenu::Remove logic") );
231
232 wxOSXMenuRemoveItem(m_hMenu , pos );
233 */
234 m_peer->Remove( item );
235 // and from internal data structures
236 return wxMenuBase::DoRemove(item);
237 }
238
239 void wxMenu::SetTitle(const wxString& label)
240 {
241 m_title = label ;
242 m_peer->SetTitle( wxStripMenuCodes( label ) );
243 }
244
245 bool wxMenu::ProcessCommand(wxCommandEvent & event)
246 {
247 bool processed = false;
248
249 // Try the menu's event handler
250 if ( /* !processed && */ GetEventHandler())
251 processed = GetEventHandler()->SafelyProcessEvent(event);
252
253 // Try the window the menu was popped up from
254 // (and up through the hierarchy)
255 wxWindow *win = GetWindow();
256 if ( !processed && win )
257 processed = win->HandleWindowEvent(event);
258
259 return processed;
260 }
261
262 // ---------------------------------------------------------------------------
263 // other
264 // ---------------------------------------------------------------------------
265
266 // MacOS needs to know about submenus somewhere within this menu
267 // before it can be displayed, also hide special menu items
268 // like preferences that are handled by the OS
269 void wxMenu::DoRearrange()
270 {
271 if ( !AllowRearrange() )
272 return;
273
274 wxMenuItem* previousItem = NULL ;
275 size_t pos ;
276 wxMenuItemList::compatibility_iterator node;
277 wxMenuItem *item;
278
279 for (pos = 0, node = GetMenuItems().GetFirst(); node; node = node->GetNext(), pos++)
280 {
281 item = (wxMenuItem *)node->GetData();
282 wxMenu* subMenu = item->GetSubMenu() ;
283 if (subMenu)
284 {
285 // already done
286 }
287 else // normal item
288 {
289 // what we do here is to hide the special items which are
290 // shown in the application menu anyhow -- it doesn't make
291 // sense to show them in their normal place as well
292 if ( item->GetId() == wxApp::s_macAboutMenuItemId ||
293 item->GetId() == wxApp::s_macPreferencesMenuItemId ||
294 item->GetId() == wxApp::s_macExitMenuItemId )
295
296 {
297 item->GetPeer()->Hide( true );
298
299 // also check for a separator which was used just to
300 // separate this item from the others, so don't leave
301 // separator at the menu start or end nor 2 consecutive
302 // separators
303 wxMenuItemList::compatibility_iterator nextNode = node->GetNext();
304 wxMenuItem *next = nextNode ? nextNode->GetData() : NULL;
305
306 wxMenuItem *sepToHide = 0;
307 if ( !previousItem && next && next->IsSeparator() )
308 {
309 // next (i.e. second as we must be first) item is
310 // the separator to hide
311 wxASSERT_MSG( pos == 0, wxT("should be the menu start") );
312 sepToHide = next;
313 }
314 else if ( GetMenuItems().GetCount() == pos + 1 &&
315 previousItem != NULL &&
316 previousItem->IsSeparator() )
317 {
318 // prev item is a trailing separator we want to hide
319 sepToHide = previousItem;
320 }
321 else if ( previousItem && previousItem->IsSeparator() &&
322 next && next->IsSeparator() )
323 {
324 // two consecutive separators, this is one too many
325 sepToHide = next;
326 }
327
328 if ( sepToHide )
329 {
330 // hide the separator as well
331 sepToHide->GetPeer()->Hide( true );
332 }
333 }
334 }
335
336 previousItem = item ;
337 }
338 }
339
340
341 bool wxMenu::HandleCommandUpdateStatus( wxMenuItem* item, wxWindow* senderWindow )
342 {
343 int id = item ? item->GetId() : 0;
344 wxUpdateUIEvent event(id);
345 event.SetEventObject( this );
346
347 bool processed = false;
348
349 // Try the menu's event handler
350 {
351 wxEvtHandler *handler = GetEventHandler();
352 if ( handler )
353 processed = handler->ProcessEvent(event);
354 }
355
356 // Try the window the menu was popped up from
357 // (and up through the hierarchy)
358 if ( !processed )
359 {
360 wxWindow *win = GetWindow();
361 if ( win )
362 processed = win->HandleWindowEvent(event);
363 }
364
365 if ( !processed && senderWindow != NULL)
366 {
367 processed = senderWindow->HandleWindowEvent(event);
368 }
369
370 if ( processed )
371 {
372 // if anything changed, update the changed attribute
373 if (event.GetSetText())
374 SetLabel(id, event.GetText());
375 if (event.GetSetChecked())
376 Check(id, event.GetChecked());
377 if (event.GetSetEnabled())
378 Enable(id, event.GetEnabled());
379 }
380 else
381 {
382 #if wxOSX_USE_CARBON
383 // these two items are also managed by the Carbon Menu Manager, therefore we must
384 // always reset them ourselves
385 UInt32 cmd = 0;
386
387 if ( id == wxApp::s_macExitMenuItemId )
388 {
389 cmd = kHICommandQuit;
390 }
391 else if (id == wxApp::s_macPreferencesMenuItemId )
392 {
393 cmd = kHICommandPreferences;
394 }
395
396 if ( cmd != 0 )
397 {
398 if ( !item->IsEnabled() || wxDialog::OSXHasModalDialogsOpen() )
399 DisableMenuCommand( NULL , cmd ) ;
400 else
401 EnableMenuCommand( NULL , cmd ) ;
402
403 }
404 #endif
405 }
406
407 return processed;
408 }
409
410 bool wxMenu::HandleCommandProcess( wxMenuItem* item, wxWindow* senderWindow )
411 {
412 int id = item ? item->GetId() : 0;
413 bool processed = false;
414 if (item->IsCheckable())
415 item->Check( !item->IsChecked() ) ;
416
417 if ( SendEvent( id , item->IsCheckable() ? item->IsChecked() : -1 ) )
418 processed = true ;
419 else
420 {
421 if ( senderWindow != NULL )
422 {
423 wxCommandEvent event(wxEVT_COMMAND_MENU_SELECTED , id);
424 event.SetEventObject(senderWindow);
425 event.SetInt(item->IsCheckable() ? item->IsChecked() : -1);
426
427 if ( senderWindow->HandleWindowEvent(event) )
428 processed = true ;
429 }
430 }
431
432 if(!processed && item)
433 {
434 processed = item->GetPeer()->DoDefault();
435 }
436
437 return processed;
438 }
439
440 void wxMenu::HandleMenuItemHighlighted( wxMenuItem* item )
441 {
442 int id = item ? item->GetId() : 0;
443 wxMenuEvent wxevent(wxEVT_MENU_HIGHLIGHT, id, this);
444 DoHandleMenuEvent( wxevent );
445 }
446
447 void wxMenu::HandleMenuOpened()
448 {
449 wxMenuEvent wxevent(wxEVT_MENU_OPEN, 0, this);
450 DoHandleMenuEvent( wxevent );
451 }
452
453 void wxMenu::HandleMenuClosed()
454 {
455 wxMenuEvent wxevent(wxEVT_MENU_CLOSE, 0, this);
456 DoHandleMenuEvent( wxevent );
457 }
458
459 bool wxMenu::DoHandleMenuEvent(wxEvent& wxevent)
460 {
461 wxevent.SetEventObject(this);
462 wxEvtHandler* handler = GetEventHandler();
463 if (handler && handler->ProcessEvent(wxevent))
464 {
465 return true;
466 }
467 else
468 {
469 wxWindow *win = GetWindow();
470 if (win)
471 {
472 if ( win->HandleWindowEvent(wxevent) )
473 return true;
474 }
475 }
476 return false;
477 }
478
479 // Menu Bar
480
481 /*
482
483 Mac Implementation note :
484
485 The Mac has only one global menubar, so we attempt to install the currently
486 active menubar from a frame, we currently don't take into account mdi-frames
487 which would ask for menu-merging
488
489 Secondly there is no mac api for changing a menubar that is not the current
490 menubar, so we have to wait for preparing the actual menubar until the
491 wxMenubar is to be used
492
493 We can in subsequent versions use MacInstallMenuBar to provide some sort of
494 auto-merge for MDI in case this will be necessary
495
496 */
497
498 wxMenuBar* wxMenuBar::s_macInstalledMenuBar = NULL ;
499 wxMenuBar* wxMenuBar::s_macCommonMenuBar = NULL ;
500 bool wxMenuBar::s_macAutoWindowMenu = true ;
501 WXHMENU wxMenuBar::s_macWindowMenuHandle = NULL ;
502
503 void wxMenuBar::Init()
504 {
505 m_eventHandler = this;
506 m_menuBarFrame = NULL;
507 m_rootMenu = new wxMenu();
508 m_rootMenu->Attach(this);
509
510 m_appleMenu = new wxMenu();
511 m_appleMenu->SetAllowRearrange(false);
512
513 // Create standard items unless the application explicitly disabled this by
514 // setting the corresponding ids to wxID_NONE: although this is not
515 // recommended, sometimes these items really don't make sense.
516 if ( wxApp::s_macAboutMenuItemId != wxID_NONE )
517 {
518 wxString aboutLabel(_("About"));
519 if ( wxTheApp )
520 aboutLabel << ' ' << wxTheApp->GetAppDisplayName();
521 else
522 aboutLabel << "...";
523 m_appleMenu->Append( wxApp::s_macAboutMenuItemId, aboutLabel);
524 m_appleMenu->AppendSeparator();
525 }
526
527 #if !wxOSX_USE_CARBON
528 if ( wxApp::s_macPreferencesMenuItemId != wxID_NONE )
529 {
530 m_appleMenu->Append( wxApp::s_macPreferencesMenuItemId,
531 _("Preferences...") + "\tCtrl+," );
532 m_appleMenu->AppendSeparator();
533 }
534
535 // standard menu items, handled in wxMenu::HandleCommandProcess(), see above:
536 wxString hideLabel(_("Hide"));
537 if ( wxTheApp )
538 hideLabel << ' ' << wxTheApp->GetAppDisplayName();
539 hideLabel << "\tCtrl+H";
540 m_appleMenu->Append( wxID_OSX_HIDE, hideLabel );
541 m_appleMenu->Append( wxID_OSX_HIDEOTHERS, _("Hide Others")+"\tAlt+Ctrl+H" );
542 m_appleMenu->Append( wxID_OSX_SHOWALL, _("Show All") );
543 m_appleMenu->AppendSeparator();
544
545 // Do always add "Quit" item unconditionally however, it can't be disabled.
546 wxString quitLabel(_("Quit"));
547 if ( wxTheApp )
548 quitLabel << ' ' << wxTheApp->GetAppDisplayName();
549 quitLabel << "\tCtrl+Q";
550 m_appleMenu->Append( wxApp::s_macExitMenuItemId, quitLabel );
551 #endif // !wxOSX_USE_CARBON
552
553 m_rootMenu->AppendSubMenu(m_appleMenu, "\x14") ;
554 }
555
556 wxMenuBar::wxMenuBar()
557 {
558 Init();
559 }
560
561 wxMenuBar::wxMenuBar( long WXUNUSED(style) )
562 {
563 Init();
564 }
565
566 wxMenuBar::wxMenuBar(size_t count, wxMenu *menus[], const wxString titles[], long WXUNUSED(style))
567 {
568 Init();
569
570 m_titles.Alloc(count);
571
572 for ( size_t i = 0; i < count; i++ )
573 {
574 m_menus.Append(menus[i]);
575 m_titles.Add(titles[i]);
576
577 menus[i]->Attach(this);
578 Append( menus[i], titles[i] );
579 }
580 }
581
582 wxMenuBar::~wxMenuBar()
583 {
584 if (s_macCommonMenuBar == this)
585 s_macCommonMenuBar = NULL;
586
587 if (s_macInstalledMenuBar == this)
588 {
589 s_macInstalledMenuBar = NULL;
590 }
591 }
592
593 void wxMenuBar::Refresh(bool WXUNUSED(eraseBackground), const wxRect *WXUNUSED(rect))
594 {
595 wxCHECK_RET( IsAttached(), wxT("can't refresh unatteched menubar") );
596 }
597
598 void wxMenuBar::MacInstallMenuBar()
599 {
600 if ( s_macInstalledMenuBar == this )
601 return ;
602
603 m_rootMenu->GetPeer()->MakeRoot();
604
605 #if 0
606
607 MenuBarHandle menubar = NULL ;
608
609 menubar = NewHandleClear( 6 /* sizeof( MenuBarHeader ) */ ) ;
610
611 ::SetMenuBar( menubar ) ;
612 DisposeMenuBar( menubar ) ;
613 MenuHandle appleMenu = NULL ;
614
615 verify_noerr( CreateNewMenu( kwxMacAppleMenuId , 0 , &appleMenu ) ) ;
616 verify_noerr( SetMenuTitleWithCFString( appleMenu , CFSTR( "\x14" ) ) );
617
618 // Add About/Preferences separator only on OS X
619 // KH/RN: Separator is always present on 10.3 but not on 10.2
620 // However, the change from 10.2 to 10.3 suggests it is preferred
621 InsertMenuItemTextWithCFString( appleMenu,
622 CFSTR(""), 0, kMenuItemAttrSeparator, 0);
623 InsertMenuItemTextWithCFString( appleMenu,
624 CFSTR("About..."), 0, 0, 0);
625 MacInsertMenu( appleMenu , 0 ) ;
626
627 // if we have a mac help menu, clean it up before adding new items
628 MenuHandle helpMenuHandle ;
629 MenuItemIndex firstUserHelpMenuItem ;
630
631 if ( UMAGetHelpMenuDontCreate( &helpMenuHandle , &firstUserHelpMenuItem) == noErr )
632 {
633 for ( int i = CountMenuItems( helpMenuHandle ) ; i >= firstUserHelpMenuItem ; --i )
634 DeleteMenuItem( helpMenuHandle , i ) ;
635 }
636 else
637 {
638 helpMenuHandle = NULL ;
639 }
640
641 if ( wxApp::s_macPreferencesMenuItemId)
642 {
643 wxMenuItem *item = FindItem( wxApp::s_macPreferencesMenuItemId , NULL ) ;
644 if ( item == NULL || !(item->IsEnabled()) )
645 DisableMenuCommand( NULL , kHICommandPreferences ) ;
646 else
647 EnableMenuCommand( NULL , kHICommandPreferences ) ;
648 }
649
650 // Unlike preferences which may or may not exist, the Quit item should be always
651 // enabled unless it is added by the application and then disabled, otherwise
652 // a program would be required to add an item with wxID_EXIT in order to get the
653 // Quit menu item to be enabled, which seems a bit burdensome.
654 if ( wxApp::s_macExitMenuItemId)
655 {
656 wxMenuItem *item = FindItem( wxApp::s_macExitMenuItemId , NULL ) ;
657 if ( item != NULL && !(item->IsEnabled()) )
658 DisableMenuCommand( NULL , kHICommandQuit ) ;
659 else
660 EnableMenuCommand( NULL , kHICommandQuit ) ;
661 }
662
663 wxString strippedHelpMenuTitle = wxStripMenuCodes( wxApp::s_macHelpMenuTitleName ) ;
664 wxString strippedTranslatedHelpMenuTitle = wxStripMenuCodes( wxString( _("&Help") ) ) ;
665 wxMenuList::compatibility_iterator menuIter = m_menus.GetFirst();
666 for (size_t i = 0; i < m_menus.GetCount(); i++, menuIter = menuIter->GetNext())
667 {
668 wxMenuItemList::compatibility_iterator node;
669 wxMenuItem *item;
670 wxMenu* menu = menuIter->GetData() , *subMenu = NULL ;
671 wxString strippedMenuTitle = wxStripMenuCodes(m_titles[i]);
672
673 if ( strippedMenuTitle == wxT("?") || strippedMenuTitle == strippedHelpMenuTitle || strippedMenuTitle == strippedTranslatedHelpMenuTitle )
674 {
675 for (node = menu->GetMenuItems().GetFirst(); node; node = node->GetNext())
676 {
677 item = (wxMenuItem *)node->GetData();
678 subMenu = item->GetSubMenu() ;
679 if (subMenu)
680 {
681 UMAAppendMenuItem(mh, wxStripMenuCodes(item->GetText()) , wxFont::GetDefaultEncoding() );
682 MenuItemIndex position = CountMenuItems(mh);
683 ::SetMenuItemHierarchicalMenu(mh, position, MAC_WXHMENU(subMenu->GetHMenu()));
684 }
685 else
686 {
687 if ( item->GetId() != wxApp::s_macAboutMenuItemId )
688 {
689 // we have found a user help menu and an item other than the about item,
690 // so we can create the mac help menu now, if we haven't created it yet
691 if ( helpMenuHandle == NULL )
692 {
693 if ( UMAGetHelpMenu( &helpMenuHandle , &firstUserHelpMenuItem) != noErr )
694 {
695 helpMenuHandle = NULL ;
696 break ;
697 }
698 }
699 }
700
701 if ( item->IsSeparator() )
702 {
703 if ( helpMenuHandle )
704 AppendMenuItemTextWithCFString( helpMenuHandle,
705 CFSTR(""), kMenuItemAttrSeparator, 0,NULL);
706 }
707 else
708 {
709 wxAcceleratorEntry*
710 entry = wxAcceleratorEntry::Create( item->GetItemLabel() ) ;
711
712 if ( item->GetId() == wxApp::s_macAboutMenuItemId )
713 {
714 // this will be taken care of below
715 }
716 else
717 {
718 if ( helpMenuHandle )
719 {
720 UMAAppendMenuItem(helpMenuHandle, wxStripMenuCodes(item->GetItemLabel()) , wxFont::GetDefaultEncoding(), entry);
721 SetMenuItemCommandID( helpMenuHandle , CountMenuItems(helpMenuHandle) , wxIdToMacCommand ( item->GetId() ) ) ;
722 SetMenuItemRefCon( helpMenuHandle , CountMenuItems(helpMenuHandle) , (URefCon) item ) ;
723 }
724 }
725
726 delete entry ;
727 }
728 }
729 }
730 }
731
732 else if ( ( m_titles[i] == wxT("Window") || m_titles[i] == wxT("&Window") )
733 && GetAutoWindowMenu() )
734 {
735 if ( MacGetWindowMenuHMenu() == NULL )
736 {
737 CreateStandardWindowMenu( 0 , (MenuHandle*) &s_macWindowMenuHandle ) ;
738 }
739
740 MenuRef wm = (MenuRef)MacGetWindowMenuHMenu();
741 if ( wm == NULL )
742 break;
743
744 // get the insertion point in the standard menu
745 MenuItemIndex winListStart;
746 GetIndMenuItemWithCommandID(wm,
747 kHICommandWindowListSeparator, 1, NULL, &winListStart);
748
749 // add a separator so that the standard items and the custom items
750 // aren't mixed together, but only if this is the first run
751 OSStatus err = GetIndMenuItemWithCommandID(wm,
752 'WXWM', 1, NULL, NULL);
753
754 if ( err == menuItemNotFoundErr )
755 {
756 InsertMenuItemTextWithCFString( wm,
757 CFSTR(""), winListStart-1, kMenuItemAttrSeparator, 'WXWM');
758 }
759
760 wxInsertMenuItemsInMenu(menu, wm, winListStart);
761 }
762 else
763 {
764 UMASetMenuTitle( MAC_WXHMENU(menu->GetHMenu()) , m_titles[i], GetFont().GetEncoding() ) ;
765 menu->MacBeforeDisplay(false) ;
766
767 ::InsertMenu(MAC_WXHMENU(GetMenu(i)->GetHMenu()), 0);
768 }
769 }
770
771 // take care of the about menu item wherever it is
772 {
773 wxMenu* aboutMenu ;
774 wxMenuItem *aboutMenuItem = FindItem(wxApp::s_macAboutMenuItemId , &aboutMenu) ;
775 if ( aboutMenuItem )
776 {
777 wxAcceleratorEntry*
778 entry = wxAcceleratorEntry::Create( aboutMenuItem->GetItemLabel() ) ;
779 UMASetMenuItemText( GetMenuHandle( kwxMacAppleMenuId ) , 1 , wxStripMenuCodes ( aboutMenuItem->GetItemLabel() ) , wxFont::GetDefaultEncoding() );
780 UMAEnableMenuItem( GetMenuHandle( kwxMacAppleMenuId ) , 1 , true );
781 SetMenuItemCommandID( GetMenuHandle( kwxMacAppleMenuId ) , 1 , kHICommandAbout ) ;
782 SetMenuItemRefCon(GetMenuHandle( kwxMacAppleMenuId ) , 1 , (URefCon)aboutMenuItem ) ;
783 UMASetMenuItemShortcut( GetMenuHandle( kwxMacAppleMenuId ) , 1 , entry ) ;
784 delete entry;
785 }
786 }
787
788 if ( GetAutoWindowMenu() )
789 {
790 if ( MacGetWindowMenuHMenu() == NULL )
791 CreateStandardWindowMenu( 0 , (MenuHandle*) &s_macWindowMenuHandle ) ;
792
793 InsertMenu( (MenuHandle) MacGetWindowMenuHMenu() , 0 ) ;
794 }
795
796 ::DrawMenuBar() ;
797 #endif
798
799 s_macInstalledMenuBar = this;
800 }
801
802 void wxMenuBar::EnableTop(size_t pos, bool enable)
803 {
804 wxCHECK_RET( IsAttached(), wxT("doesn't work with unattached menubars") );
805
806 m_rootMenu->FindItemByPosition( pos )->Enable(enable);
807
808 Refresh();
809 }
810
811 bool wxMenuBar::Enable(bool enable)
812 {
813 wxCHECK_MSG( IsAttached(), false, wxT("doesn't work with unattached menubars") );
814
815 size_t i;
816 for (i = 0; i < GetMenuCount(); i++)
817 EnableTop(i, enable);
818
819 return true;
820 }
821
822 void wxMenuBar::SetMenuLabel(size_t pos, const wxString& label)
823 {
824 wxCHECK_RET( pos < GetMenuCount(), wxT("invalid menu index") );
825
826 m_titles[pos] = label;
827
828 if ( !IsAttached() )
829 return;
830
831 GetMenu(pos)->SetTitle( label ) ;
832 }
833
834 wxString wxMenuBar::GetMenuLabel(size_t pos) const
835 {
836 wxCHECK_MSG( pos < GetMenuCount(), wxEmptyString,
837 wxT("invalid menu index in wxMenuBar::GetMenuLabel") );
838
839 return m_titles[pos];
840 }
841
842 int wxMenuBar::FindMenu(const wxString& title)
843 {
844 wxString menuTitle = wxStripMenuCodes(title);
845
846 size_t count = GetMenuCount();
847 for ( size_t i = 0; i < count; i++ )
848 {
849 wxString title = wxStripMenuCodes(m_titles[i]);
850 if ( menuTitle == title )
851 return i;
852 }
853
854 return wxNOT_FOUND;
855 }
856
857 // ---------------------------------------------------------------------------
858 // wxMenuBar construction
859 // ---------------------------------------------------------------------------
860
861 const int firstMenuPos = 1; // to account for the 0th application menu on mac
862
863 wxMenu *wxMenuBar::Replace(size_t pos, wxMenu *menu, const wxString& title)
864 {
865 wxMenu *menuOld = wxMenuBarBase::Replace(pos, menu, title);
866 if ( !menuOld )
867 return NULL;
868
869 m_titles[pos] = title;
870
871 wxMenuItem* item = m_rootMenu->FindItemByPosition(pos+firstMenuPos);
872 m_rootMenu->Remove(item);
873 m_rootMenu->Insert( pos+firstMenuPos, wxMenuItem::New( m_rootMenu, wxID_ANY, title, "", wxITEM_NORMAL, menu ) );
874
875 return menuOld;
876 }
877
878 bool wxMenuBar::Insert(size_t pos, wxMenu *menu, const wxString& title)
879 {
880 if ( !wxMenuBarBase::Insert(pos, menu, title) )
881 return false;
882
883 m_titles.Insert(title, pos);
884
885 m_rootMenu->Insert( pos+firstMenuPos, wxMenuItem::New( m_rootMenu, wxID_ANY, title, "", wxITEM_NORMAL, menu ) );
886
887 return true;
888 }
889
890 wxMenu *wxMenuBar::Remove(size_t pos)
891 {
892 wxMenu *menu = wxMenuBarBase::Remove(pos);
893 if ( !menu )
894 return NULL;
895
896 wxMenuItem* item = m_rootMenu->FindItemByPosition(pos+firstMenuPos);
897 m_rootMenu->Remove(item);
898
899 m_titles.RemoveAt(pos);
900
901 return menu;
902 }
903
904 bool wxMenuBar::Append(wxMenu *menu, const wxString& title)
905 {
906 WXHMENU submenu = menu ? menu->GetHMenu() : 0;
907 wxCHECK_MSG( submenu, false, wxT("can't append invalid menu to menubar") );
908
909 if ( !wxMenuBarBase::Append(menu, title) )
910 return false;
911
912 m_titles.Add(title);
913
914 m_rootMenu->AppendSubMenu(menu, title);
915
916 return true;
917 }
918
919 void wxMenuBar::Detach()
920 {
921 wxMenuBarBase::Detach() ;
922 }
923
924 void wxMenuBar::Attach(wxFrame *frame)
925 {
926 wxMenuBarBase::Attach( frame ) ;
927 }
928
929 // ---------------------------------------------------------------------------
930 // wxMenuBar searching for menu items
931 // ---------------------------------------------------------------------------
932
933 // Find the itemString in menuString, and return the item id or wxNOT_FOUND
934 int wxMenuBar::FindMenuItem(const wxString& menuString,
935 const wxString& itemString) const
936 {
937 wxString menuLabel = wxStripMenuCodes(menuString);
938 size_t count = GetMenuCount();
939 for ( size_t i = 0; i < count; i++ )
940 {
941 wxString title = wxStripMenuCodes(m_titles[i]);
942 if ( menuLabel == title )
943 return GetMenu(i)->FindItem(itemString);
944 }
945
946 return wxNOT_FOUND;
947 }
948
949 wxMenuItem *wxMenuBar::FindItem(int id, wxMenu **itemMenu) const
950 {
951 if ( itemMenu )
952 *itemMenu = NULL;
953
954 wxMenuItem *item = NULL;
955 size_t count = GetMenuCount();
956 for ( size_t i = 0; !item && (i < count); i++ )
957 item = GetMenu(i)->FindItem(id, itemMenu);
958
959 return item;
960 }
961
962 #endif