Store menus titles in menus themselves in wxOSX.
[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 for ( size_t i = 0; i < count; i++ )
571 {
572 m_menus.Append(menus[i]);
573
574 menus[i]->Attach(this);
575 Append( menus[i], titles[i] );
576 }
577 }
578
579 wxMenuBar::~wxMenuBar()
580 {
581 if (s_macCommonMenuBar == this)
582 s_macCommonMenuBar = NULL;
583
584 if (s_macInstalledMenuBar == this)
585 {
586 s_macInstalledMenuBar = NULL;
587 }
588 }
589
590 void wxMenuBar::Refresh(bool WXUNUSED(eraseBackground), const wxRect *WXUNUSED(rect))
591 {
592 wxCHECK_RET( IsAttached(), wxT("can't refresh unatteched menubar") );
593 }
594
595 void wxMenuBar::MacInstallMenuBar()
596 {
597 if ( s_macInstalledMenuBar == this )
598 return ;
599
600 m_rootMenu->GetPeer()->MakeRoot();
601
602 #if 0
603
604 MenuBarHandle menubar = NULL ;
605
606 menubar = NewHandleClear( 6 /* sizeof( MenuBarHeader ) */ ) ;
607
608 ::SetMenuBar( menubar ) ;
609 DisposeMenuBar( menubar ) ;
610 MenuHandle appleMenu = NULL ;
611
612 verify_noerr( CreateNewMenu( kwxMacAppleMenuId , 0 , &appleMenu ) ) ;
613 verify_noerr( SetMenuTitleWithCFString( appleMenu , CFSTR( "\x14" ) ) );
614
615 // Add About/Preferences separator only on OS X
616 // KH/RN: Separator is always present on 10.3 but not on 10.2
617 // However, the change from 10.2 to 10.3 suggests it is preferred
618 InsertMenuItemTextWithCFString( appleMenu,
619 CFSTR(""), 0, kMenuItemAttrSeparator, 0);
620 InsertMenuItemTextWithCFString( appleMenu,
621 CFSTR("About..."), 0, 0, 0);
622 MacInsertMenu( appleMenu , 0 ) ;
623
624 // if we have a mac help menu, clean it up before adding new items
625 MenuHandle helpMenuHandle ;
626 MenuItemIndex firstUserHelpMenuItem ;
627
628 if ( UMAGetHelpMenuDontCreate( &helpMenuHandle , &firstUserHelpMenuItem) == noErr )
629 {
630 for ( int i = CountMenuItems( helpMenuHandle ) ; i >= firstUserHelpMenuItem ; --i )
631 DeleteMenuItem( helpMenuHandle , i ) ;
632 }
633 else
634 {
635 helpMenuHandle = NULL ;
636 }
637
638 if ( wxApp::s_macPreferencesMenuItemId)
639 {
640 wxMenuItem *item = FindItem( wxApp::s_macPreferencesMenuItemId , NULL ) ;
641 if ( item == NULL || !(item->IsEnabled()) )
642 DisableMenuCommand( NULL , kHICommandPreferences ) ;
643 else
644 EnableMenuCommand( NULL , kHICommandPreferences ) ;
645 }
646
647 // Unlike preferences which may or may not exist, the Quit item should be always
648 // enabled unless it is added by the application and then disabled, otherwise
649 // a program would be required to add an item with wxID_EXIT in order to get the
650 // Quit menu item to be enabled, which seems a bit burdensome.
651 if ( wxApp::s_macExitMenuItemId)
652 {
653 wxMenuItem *item = FindItem( wxApp::s_macExitMenuItemId , NULL ) ;
654 if ( item != NULL && !(item->IsEnabled()) )
655 DisableMenuCommand( NULL , kHICommandQuit ) ;
656 else
657 EnableMenuCommand( NULL , kHICommandQuit ) ;
658 }
659
660 wxString strippedHelpMenuTitle = wxStripMenuCodes( wxApp::s_macHelpMenuTitleName ) ;
661 wxString strippedTranslatedHelpMenuTitle = wxStripMenuCodes( wxString( _("&Help") ) ) ;
662 wxMenuList::compatibility_iterator menuIter = m_menus.GetFirst();
663 for (size_t i = 0; i < m_menus.GetCount(); i++, menuIter = menuIter->GetNext())
664 {
665 wxMenuItemList::compatibility_iterator node;
666 wxMenuItem *item;
667 wxMenu* menu = menuIter->GetData() , *subMenu = NULL ;
668 wxString strippedMenuTitle = wxStripMenuCodes(m_titles[i]);
669
670 if ( strippedMenuTitle == wxT("?") || strippedMenuTitle == strippedHelpMenuTitle || strippedMenuTitle == strippedTranslatedHelpMenuTitle )
671 {
672 for (node = menu->GetMenuItems().GetFirst(); node; node = node->GetNext())
673 {
674 item = (wxMenuItem *)node->GetData();
675 subMenu = item->GetSubMenu() ;
676 if (subMenu)
677 {
678 UMAAppendMenuItem(mh, wxStripMenuCodes(item->GetText()) , wxFont::GetDefaultEncoding() );
679 MenuItemIndex position = CountMenuItems(mh);
680 ::SetMenuItemHierarchicalMenu(mh, position, MAC_WXHMENU(subMenu->GetHMenu()));
681 }
682 else
683 {
684 if ( item->GetId() != wxApp::s_macAboutMenuItemId )
685 {
686 // we have found a user help menu and an item other than the about item,
687 // so we can create the mac help menu now, if we haven't created it yet
688 if ( helpMenuHandle == NULL )
689 {
690 if ( UMAGetHelpMenu( &helpMenuHandle , &firstUserHelpMenuItem) != noErr )
691 {
692 helpMenuHandle = NULL ;
693 break ;
694 }
695 }
696 }
697
698 if ( item->IsSeparator() )
699 {
700 if ( helpMenuHandle )
701 AppendMenuItemTextWithCFString( helpMenuHandle,
702 CFSTR(""), kMenuItemAttrSeparator, 0,NULL);
703 }
704 else
705 {
706 wxAcceleratorEntry*
707 entry = wxAcceleratorEntry::Create( item->GetItemLabel() ) ;
708
709 if ( item->GetId() == wxApp::s_macAboutMenuItemId )
710 {
711 // this will be taken care of below
712 }
713 else
714 {
715 if ( helpMenuHandle )
716 {
717 UMAAppendMenuItem(helpMenuHandle, wxStripMenuCodes(item->GetItemLabel()) , wxFont::GetDefaultEncoding(), entry);
718 SetMenuItemCommandID( helpMenuHandle , CountMenuItems(helpMenuHandle) , wxIdToMacCommand ( item->GetId() ) ) ;
719 SetMenuItemRefCon( helpMenuHandle , CountMenuItems(helpMenuHandle) , (URefCon) item ) ;
720 }
721 }
722
723 delete entry ;
724 }
725 }
726 }
727 }
728
729 else if ( ( m_titles[i] == wxT("Window") || m_titles[i] == wxT("&Window") )
730 && GetAutoWindowMenu() )
731 {
732 if ( MacGetWindowMenuHMenu() == NULL )
733 {
734 CreateStandardWindowMenu( 0 , (MenuHandle*) &s_macWindowMenuHandle ) ;
735 }
736
737 MenuRef wm = (MenuRef)MacGetWindowMenuHMenu();
738 if ( wm == NULL )
739 break;
740
741 // get the insertion point in the standard menu
742 MenuItemIndex winListStart;
743 GetIndMenuItemWithCommandID(wm,
744 kHICommandWindowListSeparator, 1, NULL, &winListStart);
745
746 // add a separator so that the standard items and the custom items
747 // aren't mixed together, but only if this is the first run
748 OSStatus err = GetIndMenuItemWithCommandID(wm,
749 'WXWM', 1, NULL, NULL);
750
751 if ( err == menuItemNotFoundErr )
752 {
753 InsertMenuItemTextWithCFString( wm,
754 CFSTR(""), winListStart-1, kMenuItemAttrSeparator, 'WXWM');
755 }
756
757 wxInsertMenuItemsInMenu(menu, wm, winListStart);
758 }
759 else
760 {
761 UMASetMenuTitle( MAC_WXHMENU(menu->GetHMenu()) , m_titles[i], GetFont().GetEncoding() ) ;
762 menu->MacBeforeDisplay(false) ;
763
764 ::InsertMenu(MAC_WXHMENU(GetMenu(i)->GetHMenu()), 0);
765 }
766 }
767
768 // take care of the about menu item wherever it is
769 {
770 wxMenu* aboutMenu ;
771 wxMenuItem *aboutMenuItem = FindItem(wxApp::s_macAboutMenuItemId , &aboutMenu) ;
772 if ( aboutMenuItem )
773 {
774 wxAcceleratorEntry*
775 entry = wxAcceleratorEntry::Create( aboutMenuItem->GetItemLabel() ) ;
776 UMASetMenuItemText( GetMenuHandle( kwxMacAppleMenuId ) , 1 , wxStripMenuCodes ( aboutMenuItem->GetItemLabel() ) , wxFont::GetDefaultEncoding() );
777 UMAEnableMenuItem( GetMenuHandle( kwxMacAppleMenuId ) , 1 , true );
778 SetMenuItemCommandID( GetMenuHandle( kwxMacAppleMenuId ) , 1 , kHICommandAbout ) ;
779 SetMenuItemRefCon(GetMenuHandle( kwxMacAppleMenuId ) , 1 , (URefCon)aboutMenuItem ) ;
780 UMASetMenuItemShortcut( GetMenuHandle( kwxMacAppleMenuId ) , 1 , entry ) ;
781 delete entry;
782 }
783 }
784
785 if ( GetAutoWindowMenu() )
786 {
787 if ( MacGetWindowMenuHMenu() == NULL )
788 CreateStandardWindowMenu( 0 , (MenuHandle*) &s_macWindowMenuHandle ) ;
789
790 InsertMenu( (MenuHandle) MacGetWindowMenuHMenu() , 0 ) ;
791 }
792
793 ::DrawMenuBar() ;
794 #endif
795
796 s_macInstalledMenuBar = this;
797 }
798
799 void wxMenuBar::EnableTop(size_t pos, bool enable)
800 {
801 wxCHECK_RET( IsAttached(), wxT("doesn't work with unattached menubars") );
802
803 m_rootMenu->FindItemByPosition( pos )->Enable(enable);
804
805 Refresh();
806 }
807
808 bool wxMenuBar::Enable(bool enable)
809 {
810 wxCHECK_MSG( IsAttached(), false, wxT("doesn't work with unattached menubars") );
811
812 size_t i;
813 for (i = 0; i < GetMenuCount(); i++)
814 EnableTop(i, enable);
815
816 return true;
817 }
818
819 void wxMenuBar::SetMenuLabel(size_t pos, const wxString& label)
820 {
821 wxCHECK_RET( pos < GetMenuCount(), wxT("invalid menu index") );
822
823 GetMenu(pos)->SetTitle( label ) ;
824 }
825
826 wxString wxMenuBar::GetMenuLabel(size_t pos) const
827 {
828 wxCHECK_MSG( pos < GetMenuCount(), wxEmptyString,
829 wxT("invalid menu index in wxMenuBar::GetMenuLabel") );
830
831 return GetMenu(pos)->GetTitle();
832 }
833
834 // ---------------------------------------------------------------------------
835 // wxMenuBar construction
836 // ---------------------------------------------------------------------------
837
838 const int firstMenuPos = 1; // to account for the 0th application menu on mac
839
840 wxMenu *wxMenuBar::Replace(size_t pos, wxMenu *menu, const wxString& title)
841 {
842 wxMenu *menuOld = wxMenuBarBase::Replace(pos, menu, title);
843 if ( !menuOld )
844 return NULL;
845
846 wxMenuItem* item = m_rootMenu->FindItemByPosition(pos+firstMenuPos);
847 m_rootMenu->Remove(item);
848 m_rootMenu->Insert( pos+firstMenuPos, wxMenuItem::New( m_rootMenu, wxID_ANY, title, "", wxITEM_NORMAL, menu ) );
849
850 return menuOld;
851 }
852
853 bool wxMenuBar::Insert(size_t pos, wxMenu *menu, const wxString& title)
854 {
855 if ( !wxMenuBarBase::Insert(pos, menu, title) )
856 return false;
857
858 m_rootMenu->Insert( pos+firstMenuPos, wxMenuItem::New( m_rootMenu, wxID_ANY, title, "", wxITEM_NORMAL, menu ) );
859
860 return true;
861 }
862
863 wxMenu *wxMenuBar::Remove(size_t pos)
864 {
865 wxMenu *menu = wxMenuBarBase::Remove(pos);
866 if ( !menu )
867 return NULL;
868
869 wxMenuItem* item = m_rootMenu->FindItemByPosition(pos+firstMenuPos);
870 m_rootMenu->Remove(item);
871
872 return menu;
873 }
874
875 bool wxMenuBar::Append(wxMenu *menu, const wxString& title)
876 {
877 WXHMENU submenu = menu ? menu->GetHMenu() : 0;
878 wxCHECK_MSG( submenu, false, wxT("can't append invalid menu to menubar") );
879
880 if ( !wxMenuBarBase::Append(menu, title) )
881 return false;
882
883 m_rootMenu->AppendSubMenu(menu, title);
884 menu->SetTitle(title);
885
886 return true;
887 }
888
889 void wxMenuBar::Detach()
890 {
891 wxMenuBarBase::Detach() ;
892 }
893
894 void wxMenuBar::Attach(wxFrame *frame)
895 {
896 wxMenuBarBase::Attach( frame ) ;
897 }
898
899 #endif // wxUSE_MENUS