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