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