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