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