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