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