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