]> git.saurik.com Git - wxWidgets.git/blame - src/osx/menu_osx.cpp
adapting inheritance to other osx ports
[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 }
c46d0503
SC
443
444 if(!processed && item)
445 {
446 processed = item->GetPeer()->DoDefault();
447 }
448
524c47aa
SC
449 return processed;
450}
451
452void wxMenu::HandleMenuItemHighlighted( wxMenuItem* item )
453{
454 int id = item ? item->GetId() : 0;
455 wxMenuEvent wxevent(wxEVT_MENU_HIGHLIGHT, id, this);
456 DoHandleMenuEvent( wxevent );
457}
458
459void wxMenu::HandleMenuOpened()
460{
461 wxMenuEvent wxevent(wxEVT_MENU_OPEN, 0, this);
462 DoHandleMenuEvent( wxevent );
463}
464
465void wxMenu::HandleMenuClosed()
466{
467 wxMenuEvent wxevent(wxEVT_MENU_CLOSE, 0, this);
468 DoHandleMenuEvent( wxevent );
469}
470
471bool wxMenu::DoHandleMenuEvent(wxEvent& wxevent)
472{
473 wxevent.SetEventObject(this);
474 wxEvtHandler* handler = GetEventHandler();
475 if (handler && handler->ProcessEvent(wxevent))
476 {
477 return true;
478 }
479 else
480 {
6a57bd93 481 wxWindow *win = GetWindow();
524c47aa
SC
482 if (win)
483 {
484 if ( win->HandleWindowEvent(wxevent) )
485 return true;
486 }
487 }
488 return false;
489}
490
491// Menu Bar
492
493/*
494
495Mac Implementation note :
496
497The Mac has only one global menubar, so we attempt to install the currently
498active menubar from a frame, we currently don't take into account mdi-frames
499which would ask for menu-merging
500
501Secondly there is no mac api for changing a menubar that is not the current
502menubar, so we have to wait for preparing the actual menubar until the
503wxMenubar is to be used
504
505We can in subsequent versions use MacInstallMenuBar to provide some sort of
506auto-merge for MDI in case this will be necessary
507
508*/
509
510wxMenuBar* wxMenuBar::s_macInstalledMenuBar = NULL ;
511wxMenuBar* wxMenuBar::s_macCommonMenuBar = NULL ;
512bool wxMenuBar::s_macAutoWindowMenu = true ;
513WXHMENU wxMenuBar::s_macWindowMenuHandle = NULL ;
514
515void wxMenuBar::Init()
516{
517 m_eventHandler = this;
518 m_menuBarFrame = NULL;
524c47aa 519 m_rootMenu = new wxMenu();
6a57bd93
VZ
520 m_rootMenu->Attach(this);
521
1ea5ef01
SC
522 m_appleMenu = new wxMenu();
523 m_appleMenu->SetAllowRearrange(false);
4f1b95ea
VZ
524
525 // Create standard items unless the application explicitly disabled this by
526 // setting the corresponding ids to wxID_NONE: although this is not
527 // recommended, sometimes these items really don't make sense.
528 if ( wxApp::s_macAboutMenuItemId != wxID_NONE )
529 {
c46d0503 530 wxString aboutLabel(_("About"));
c8bef6e3
VZ
531 if ( wxTheApp )
532 aboutLabel << ' ' << wxTheApp->GetAppDisplayName();
533 else
534 aboutLabel << "...";
535 m_appleMenu->Append( wxApp::s_macAboutMenuItemId, aboutLabel);
4f1b95ea
VZ
536 m_appleMenu->AppendSeparator();
537 }
538
1ea5ef01 539#if !wxOSX_USE_CARBON
4f1b95ea
VZ
540 if ( wxApp::s_macPreferencesMenuItemId != wxID_NONE )
541 {
86646f2a 542 m_appleMenu->Append( wxApp::s_macPreferencesMenuItemId,
c46d0503 543 _("Preferences...") + "\tCtrl+," );
4f1b95ea
VZ
544 m_appleMenu->AppendSeparator();
545 }
546
c46d0503
SC
547 // standard menu items, handled in wxMenu::HandleCommandProcess(), see above:
548 wxString hideLabel(_("Hide"));
549 if ( wxTheApp )
550 hideLabel << ' ' << wxTheApp->GetAppDisplayName();
551 hideLabel << "\tCtrl+H";
552 m_appleMenu->Append( wxID_OSX_HIDE, hideLabel );
553 m_appleMenu->Append( wxID_OSX_HIDEOTHERS, _("Hide Others")+"\tAlt+Ctrl+H" );
554 m_appleMenu->Append( wxID_OSX_SHOWALL, _("Show All") );
555 m_appleMenu->AppendSeparator();
556
4f1b95ea 557 // Do always add "Quit" item unconditionally however, it can't be disabled.
c46d0503
SC
558 wxString quitLabel(_("Quit"));
559 if ( wxTheApp )
560 quitLabel << ' ' << wxTheApp->GetAppDisplayName();
561 quitLabel << "\tCtrl+Q";
562 m_appleMenu->Append( wxApp::s_macExitMenuItemId, quitLabel );
4f1b95ea 563#endif // !wxOSX_USE_CARBON
524c47aa 564
1ea5ef01 565 m_rootMenu->AppendSubMenu(m_appleMenu, "\x14") ;
524c47aa
SC
566}
567
568wxMenuBar::wxMenuBar()
569{
570 Init();
571}
572
573wxMenuBar::wxMenuBar( long WXUNUSED(style) )
574{
575 Init();
576}
577
578wxMenuBar::wxMenuBar(size_t count, wxMenu *menus[], const wxString titles[], long WXUNUSED(style))
579{
580 Init();
581
582 m_titles.Alloc(count);
583
584 for ( size_t i = 0; i < count; i++ )
585 {
586 m_menus.Append(menus[i]);
587 m_titles.Add(titles[i]);
588
589 menus[i]->Attach(this);
590 Append( menus[i], titles[i] );
591 }
592}
593
594wxMenuBar::~wxMenuBar()
595{
596 if (s_macCommonMenuBar == this)
597 s_macCommonMenuBar = NULL;
598
599 if (s_macInstalledMenuBar == this)
600 {
601 s_macInstalledMenuBar = NULL;
602 }
603}
604
605void wxMenuBar::Refresh(bool WXUNUSED(eraseBackground), const wxRect *WXUNUSED(rect))
606{
607 wxCHECK_RET( IsAttached(), wxT("can't refresh unatteched menubar") );
608}
609
610void wxMenuBar::MacInstallMenuBar()
611{
612 if ( s_macInstalledMenuBar == this )
613 return ;
03647350 614
524c47aa 615 m_rootMenu->GetPeer()->MakeRoot();
eb68a54a 616
524c47aa
SC
617#if 0
618
619 MenuBarHandle menubar = NULL ;
620
621 menubar = NewHandleClear( 6 /* sizeof( MenuBarHeader ) */ ) ;
622
623 ::SetMenuBar( menubar ) ;
624 DisposeMenuBar( menubar ) ;
625 MenuHandle appleMenu = NULL ;
626
627 verify_noerr( CreateNewMenu( kwxMacAppleMenuId , 0 , &appleMenu ) ) ;
628 verify_noerr( SetMenuTitleWithCFString( appleMenu , CFSTR( "\x14" ) ) );
629
630 // Add About/Preferences separator only on OS X
631 // KH/RN: Separator is always present on 10.3 but not on 10.2
632 // However, the change from 10.2 to 10.3 suggests it is preferred
633 InsertMenuItemTextWithCFString( appleMenu,
634 CFSTR(""), 0, kMenuItemAttrSeparator, 0);
635 InsertMenuItemTextWithCFString( appleMenu,
636 CFSTR("About..."), 0, 0, 0);
637 MacInsertMenu( appleMenu , 0 ) ;
638
639 // if we have a mac help menu, clean it up before adding new items
640 MenuHandle helpMenuHandle ;
641 MenuItemIndex firstUserHelpMenuItem ;
642
643 if ( UMAGetHelpMenuDontCreate( &helpMenuHandle , &firstUserHelpMenuItem) == noErr )
644 {
645 for ( int i = CountMenuItems( helpMenuHandle ) ; i >= firstUserHelpMenuItem ; --i )
646 DeleteMenuItem( helpMenuHandle , i ) ;
647 }
648 else
649 {
650 helpMenuHandle = NULL ;
651 }
652
653 if ( wxApp::s_macPreferencesMenuItemId)
654 {
655 wxMenuItem *item = FindItem( wxApp::s_macPreferencesMenuItemId , NULL ) ;
656 if ( item == NULL || !(item->IsEnabled()) )
657 DisableMenuCommand( NULL , kHICommandPreferences ) ;
658 else
659 EnableMenuCommand( NULL , kHICommandPreferences ) ;
660 }
661
662 // Unlike preferences which may or may not exist, the Quit item should be always
663 // enabled unless it is added by the application and then disabled, otherwise
664 // a program would be required to add an item with wxID_EXIT in order to get the
665 // Quit menu item to be enabled, which seems a bit burdensome.
666 if ( wxApp::s_macExitMenuItemId)
667 {
668 wxMenuItem *item = FindItem( wxApp::s_macExitMenuItemId , NULL ) ;
669 if ( item != NULL && !(item->IsEnabled()) )
670 DisableMenuCommand( NULL , kHICommandQuit ) ;
671 else
672 EnableMenuCommand( NULL , kHICommandQuit ) ;
673 }
674
675 wxString strippedHelpMenuTitle = wxStripMenuCodes( wxApp::s_macHelpMenuTitleName ) ;
676 wxString strippedTranslatedHelpMenuTitle = wxStripMenuCodes( wxString( _("&Help") ) ) ;
677 wxMenuList::compatibility_iterator menuIter = m_menus.GetFirst();
678 for (size_t i = 0; i < m_menus.GetCount(); i++, menuIter = menuIter->GetNext())
679 {
680 wxMenuItemList::compatibility_iterator node;
681 wxMenuItem *item;
682 wxMenu* menu = menuIter->GetData() , *subMenu = NULL ;
683 wxString strippedMenuTitle = wxStripMenuCodes(m_titles[i]);
684
685 if ( strippedMenuTitle == wxT("?") || strippedMenuTitle == strippedHelpMenuTitle || strippedMenuTitle == strippedTranslatedHelpMenuTitle )
686 {
687 for (node = menu->GetMenuItems().GetFirst(); node; node = node->GetNext())
688 {
689 item = (wxMenuItem *)node->GetData();
690 subMenu = item->GetSubMenu() ;
691 if (subMenu)
692 {
e8fdf364
JS
693 UMAAppendMenuItem(mh, wxStripMenuCodes(item->GetText()) , wxFont::GetDefaultEncoding() );
694 MenuItemIndex position = CountMenuItems(mh);
695 ::SetMenuItemHierarchicalMenu(mh, position, MAC_WXHMENU(subMenu->GetHMenu()));
524c47aa
SC
696 }
697 else
698 {
699 if ( item->GetId() != wxApp::s_macAboutMenuItemId )
700 {
701 // we have found a user help menu and an item other than the about item,
702 // so we can create the mac help menu now, if we haven't created it yet
703 if ( helpMenuHandle == NULL )
704 {
705 if ( UMAGetHelpMenu( &helpMenuHandle , &firstUserHelpMenuItem) != noErr )
706 {
707 helpMenuHandle = NULL ;
708 break ;
709 }
710 }
711 }
712
713 if ( item->IsSeparator() )
714 {
715 if ( helpMenuHandle )
716 AppendMenuItemTextWithCFString( helpMenuHandle,
717 CFSTR(""), kMenuItemAttrSeparator, 0,NULL);
718 }
719 else
720 {
721 wxAcceleratorEntry*
722 entry = wxAcceleratorEntry::Create( item->GetItemLabel() ) ;
723
724 if ( item->GetId() == wxApp::s_macAboutMenuItemId )
725 {
726 // this will be taken care of below
727 }
728 else
729 {
730 if ( helpMenuHandle )
731 {
732 UMAAppendMenuItem(helpMenuHandle, wxStripMenuCodes(item->GetItemLabel()) , wxFont::GetDefaultEncoding(), entry);
733 SetMenuItemCommandID( helpMenuHandle , CountMenuItems(helpMenuHandle) , wxIdToMacCommand ( item->GetId() ) ) ;
734 SetMenuItemRefCon( helpMenuHandle , CountMenuItems(helpMenuHandle) , (URefCon) item ) ;
735 }
736 }
737
738 delete entry ;
739 }
740 }
741 }
742 }
743
744 else if ( ( m_titles[i] == wxT("Window") || m_titles[i] == wxT("&Window") )
745 && GetAutoWindowMenu() )
746 {
747 if ( MacGetWindowMenuHMenu() == NULL )
748 {
749 CreateStandardWindowMenu( 0 , (MenuHandle*) &s_macWindowMenuHandle ) ;
750 }
751
752 MenuRef wm = (MenuRef)MacGetWindowMenuHMenu();
753 if ( wm == NULL )
754 break;
755
756 // get the insertion point in the standard menu
757 MenuItemIndex winListStart;
758 GetIndMenuItemWithCommandID(wm,
759 kHICommandWindowListSeparator, 1, NULL, &winListStart);
760
761 // add a separator so that the standard items and the custom items
762 // aren't mixed together, but only if this is the first run
763 OSStatus err = GetIndMenuItemWithCommandID(wm,
764 'WXWM', 1, NULL, NULL);
765
766 if ( err == menuItemNotFoundErr )
767 {
768 InsertMenuItemTextWithCFString( wm,
769 CFSTR(""), winListStart-1, kMenuItemAttrSeparator, 'WXWM');
770 }
771
772 wxInsertMenuItemsInMenu(menu, wm, winListStart);
773 }
774 else
775 {
776 UMASetMenuTitle( MAC_WXHMENU(menu->GetHMenu()) , m_titles[i], GetFont().GetEncoding() ) ;
777 menu->MacBeforeDisplay(false) ;
778
779 ::InsertMenu(MAC_WXHMENU(_wxMenuAt(m_menus, i)->GetHMenu()), 0);
780 }
781 }
782
783 // take care of the about menu item wherever it is
784 {
785 wxMenu* aboutMenu ;
786 wxMenuItem *aboutMenuItem = FindItem(wxApp::s_macAboutMenuItemId , &aboutMenu) ;
787 if ( aboutMenuItem )
788 {
789 wxAcceleratorEntry*
790 entry = wxAcceleratorEntry::Create( aboutMenuItem->GetItemLabel() ) ;
791 UMASetMenuItemText( GetMenuHandle( kwxMacAppleMenuId ) , 1 , wxStripMenuCodes ( aboutMenuItem->GetItemLabel() ) , wxFont::GetDefaultEncoding() );
792 UMAEnableMenuItem( GetMenuHandle( kwxMacAppleMenuId ) , 1 , true );
793 SetMenuItemCommandID( GetMenuHandle( kwxMacAppleMenuId ) , 1 , kHICommandAbout ) ;
794 SetMenuItemRefCon(GetMenuHandle( kwxMacAppleMenuId ) , 1 , (URefCon)aboutMenuItem ) ;
795 UMASetMenuItemShortcut( GetMenuHandle( kwxMacAppleMenuId ) , 1 , entry ) ;
796 delete entry;
797 }
798 }
799
800 if ( GetAutoWindowMenu() )
801 {
802 if ( MacGetWindowMenuHMenu() == NULL )
803 CreateStandardWindowMenu( 0 , (MenuHandle*) &s_macWindowMenuHandle ) ;
804
805 InsertMenu( (MenuHandle) MacGetWindowMenuHMenu() , 0 ) ;
806 }
807
808 ::DrawMenuBar() ;
809#endif
810
811 s_macInstalledMenuBar = this;
812}
813
814void wxMenuBar::EnableTop(size_t pos, bool enable)
815{
816 wxCHECK_RET( IsAttached(), wxT("doesn't work with unattached menubars") );
03647350 817
524c47aa
SC
818 m_rootMenu->FindItemByPosition( pos )->Enable(enable);
819
820 Refresh();
821}
822
823bool wxMenuBar::Enable(bool enable)
824{
825 wxCHECK_MSG( IsAttached(), false, wxT("doesn't work with unattached menubars") );
826
827 size_t i;
828 for (i = 0; i < GetMenuCount(); i++)
829 EnableTop(i, enable);
830
831 return true;
832}
833
834void wxMenuBar::SetMenuLabel(size_t pos, const wxString& label)
835{
836 wxCHECK_RET( pos < GetMenuCount(), wxT("invalid menu index") );
837
838 m_titles[pos] = label;
839
840 if ( !IsAttached() )
841 return;
842
843 _wxMenuAt(m_menus, pos)->SetTitle( label ) ;
844}
845
846wxString wxMenuBar::GetMenuLabel(size_t pos) const
847{
848 wxCHECK_MSG( pos < GetMenuCount(), wxEmptyString,
849 wxT("invalid menu index in wxMenuBar::GetMenuLabel") );
850
851 return m_titles[pos];
852}
853
854int wxMenuBar::FindMenu(const wxString& title)
855{
856 wxString menuTitle = wxStripMenuCodes(title);
857
858 size_t count = GetMenuCount();
859 for ( size_t i = 0; i < count; i++ )
860 {
861 wxString title = wxStripMenuCodes(m_titles[i]);
862 if ( menuTitle == title )
863 return i;
864 }
865
866 return wxNOT_FOUND;
867}
868
869// ---------------------------------------------------------------------------
870// wxMenuBar construction
871// ---------------------------------------------------------------------------
872
873const int firstMenuPos = 1; // to account for the 0th application menu on mac
874
875wxMenu *wxMenuBar::Replace(size_t pos, wxMenu *menu, const wxString& title)
876{
877 wxMenu *menuOld = wxMenuBarBase::Replace(pos, menu, title);
878 if ( !menuOld )
879 return NULL;
880
881 m_titles[pos] = title;
882
883 wxMenuItem* item = m_rootMenu->FindItemByPosition(pos+firstMenuPos);
884 m_rootMenu->Remove(item);
885 m_rootMenu->Insert( pos+firstMenuPos, wxMenuItem::New( m_rootMenu, wxID_ANY, title, "", wxITEM_NORMAL, menu ) );
886
524c47aa
SC
887 return menuOld;
888}
889
890bool wxMenuBar::Insert(size_t pos, wxMenu *menu, const wxString& title)
891{
892 if ( !wxMenuBarBase::Insert(pos, menu, title) )
893 return false;
894
895 m_titles.Insert(title, pos);
03647350 896
524c47aa
SC
897 m_rootMenu->Insert( pos+firstMenuPos, wxMenuItem::New( m_rootMenu, wxID_ANY, title, "", wxITEM_NORMAL, menu ) );
898
524c47aa
SC
899 return true;
900}
901
902wxMenu *wxMenuBar::Remove(size_t pos)
903{
904 wxMenu *menu = wxMenuBarBase::Remove(pos);
905 if ( !menu )
906 return NULL;
907
908 wxMenuItem* item = m_rootMenu->FindItemByPosition(pos+firstMenuPos);
909 m_rootMenu->Remove(item);
910
911 m_titles.RemoveAt(pos);
912
913 return menu;
914}
915
916bool wxMenuBar::Append(wxMenu *menu, const wxString& title)
917{
918 WXHMENU submenu = menu ? menu->GetHMenu() : 0;
919 wxCHECK_MSG( submenu, false, wxT("can't append invalid menu to menubar") );
920
921 if ( !wxMenuBarBase::Append(menu, title) )
922 return false;
923
924 m_titles.Add(title);
925
926 m_rootMenu->AppendSubMenu(menu, title);
927
524c47aa
SC
928 return true;
929}
930
524c47aa
SC
931void wxMenuBar::Detach()
932{
933 wxMenuBarBase::Detach() ;
934}
935
936void wxMenuBar::Attach(wxFrame *frame)
937{
938 wxMenuBarBase::Attach( frame ) ;
939}
940
941// ---------------------------------------------------------------------------
942// wxMenuBar searching for menu items
943// ---------------------------------------------------------------------------
944
945// Find the itemString in menuString, and return the item id or wxNOT_FOUND
946int wxMenuBar::FindMenuItem(const wxString& menuString,
947 const wxString& itemString) const
948{
949 wxString menuLabel = wxStripMenuCodes(menuString);
950 size_t count = GetMenuCount();
951 for ( size_t i = 0; i < count; i++ )
952 {
953 wxString title = wxStripMenuCodes(m_titles[i]);
954 if ( menuLabel == title )
955 return _wxMenuAt(m_menus, i)->FindItem(itemString);
956 }
957
958 return wxNOT_FOUND;
959}
960
961wxMenuItem *wxMenuBar::FindItem(int id, wxMenu **itemMenu) const
962{
963 if ( itemMenu )
964 *itemMenu = NULL;
965
966 wxMenuItem *item = NULL;
967 size_t count = GetMenuCount();
968 for ( size_t i = 0; !item && (i < count); i++ )
969 item = _wxMenuAt(m_menus, i)->FindItem(id, itemMenu);
970
971 return item;
972}
11fed901
SC
973
974#endif