]> git.saurik.com Git - wxWidgets.git/blame - src/mac/menu.cpp
don't use wxTheXXXList in wxXXX ctor/dtor, only objects explicitly created
[wxWidgets.git] / src / mac / menu.cpp
CommitLineData
e9576ca5
SC
1/////////////////////////////////////////////////////////////////////////////
2// Name: menu.cpp
3// Purpose: wxMenu, wxMenuBar, wxMenuItem
4// Author: AUTHOR
5// Modified by:
6// Created: ??/??/98
7// RCS-ID: $Id$
8// Copyright: (c) AUTHOR
9// Licence: wxWindows licence
10/////////////////////////////////////////////////////////////////////////////
11
12
13// ============================================================================
14// headers & declarations
15// ============================================================================
16
17// wxWindows headers
18// -----------------
19
20#ifdef __GNUG__
21#pragma implementation "menu.h"
22#pragma implementation "menuitem.h"
23#endif
24
03e11df5 25#include "wx/app.h"
e9576ca5
SC
26#include "wx/menu.h"
27#include "wx/menuitem.h"
03e11df5 28#include "wx/window.h"
e9576ca5
SC
29#include "wx/log.h"
30#include "wx/utils.h"
31
519cb848
SC
32#include "wx/mac/uma.h"
33
e9576ca5
SC
34// other standard headers
35// ----------------------
36#include <string.h>
37
2f1ae414 38#if !USE_SHARED_LIBRARY
e9576ca5
SC
39IMPLEMENT_DYNAMIC_CLASS(wxMenu, wxEvtHandler)
40IMPLEMENT_DYNAMIC_CLASS(wxMenuBar, wxEvtHandler)
2f1ae414 41#endif
e9576ca5 42
519cb848
SC
43// the (popup) menu title has this special id
44static const int idMenuTitle = -2;
45static int formerHelpMenuItems = 0 ;
46
47const short kwxMacMenuBarResource = 1 ;
48const short kwxMacAppleMenuId = 1 ;
49
e9576ca5
SC
50// ============================================================================
51// implementation
52// ============================================================================
53
519cb848 54
e9576ca5
SC
55// Menus
56
57// Construct a menu with optional title (then use append)
519cb848 58
f5c6eb5c 59#ifdef __DARWIN__
82ca6dbc
GD
60short wxMenu::s_macNextMenuId = 3 ;
61#else
519cb848 62short wxMenu::s_macNextMenuId = 2 ;
82ca6dbc 63#endif
519cb848 64
e7549107 65void wxMenu::Init()
e9576ca5 66{
e7549107
SC
67 m_doBreak = FALSE;
68
69 // create the menu
70 Str255 label;
2f1ae414 71 wxMenuItem::MacBuildMenuString( label, NULL , NULL , m_title , false );
e7549107
SC
72 m_macMenuId = s_macNextMenuId++;
73 wxCHECK_RET( s_macNextMenuId < 236 , "menu ids > 235 cannot be used for submenus on mac" );
72055702 74 m_hMenu = ::NewMenu(m_macMenuId, label);
e7549107
SC
75
76 if ( !m_hMenu )
77 {
78 wxLogLastError("CreatePopupMenu");
79 }
80
81 // if we have a title, insert it in the beginning of the menu
82 if ( !!m_title )
e9576ca5 83 {
519cb848 84 Append(idMenuTitle, m_title) ;
e9576ca5
SC
85 AppendSeparator() ;
86 }
e7549107 87}
e9576ca5 88
e7549107
SC
89wxMenu::~wxMenu()
90{
91 if (m_hMenu)
72055702 92 ::DisposeMenu(m_hMenu);
e9576ca5 93
e7549107
SC
94#if wxUSE_ACCEL
95 // delete accels
96 WX_CLEAR_ARRAY(m_accels);
97#endif // wxUSE_ACCEL
e9576ca5
SC
98}
99
e7549107 100void wxMenu::Break()
e9576ca5 101{
e7549107
SC
102 // not available on the mac platform
103}
e9576ca5 104
e7549107 105#if wxUSE_ACCEL
e9576ca5 106
e7549107
SC
107int wxMenu::FindAccel(int id) const
108{
109 size_t n, count = m_accels.GetCount();
110 for ( n = 0; n < count; n++ )
111 {
112 if ( m_accels[n]->m_command == id )
113 return n;
e9576ca5 114 }
e7549107
SC
115
116 return wxNOT_FOUND;
e9576ca5
SC
117}
118
e7549107 119void wxMenu::UpdateAccel(wxMenuItem *item)
e9576ca5 120{
e7549107
SC
121 // find the (new) accel for this item
122 wxAcceleratorEntry *accel = wxGetAccelFromString(item->GetText());
123 if ( accel )
124 accel->m_command = item->GetId();
125
126 // find the old one
127 int n = FindAccel(item->GetId());
128 if ( n == wxNOT_FOUND )
129 {
130 // no old, add new if any
131 if ( accel )
132 m_accels.Add(accel);
133 else
134 return; // skipping RebuildAccelTable() below
135 }
136 else
137 {
138 // replace old with new or just remove the old one if no new
139 delete m_accels[n];
140 if ( accel )
141 m_accels[n] = accel;
142 else
3ef585df 143 m_accels.RemoveAt(n);
e7549107
SC
144 }
145
146 if ( IsAttached() )
147 {
148 m_menuBar->RebuildAccelTable();
149 }
e9576ca5
SC
150}
151
e7549107
SC
152#endif // wxUSE_ACCEL
153
e9576ca5 154// function appends a new item or submenu to the menu
e7549107
SC
155// append a new item or submenu to the menu
156bool wxMenu::DoInsertOrAppend(wxMenuItem *pItem, size_t pos)
e9576ca5 157{
e7549107
SC
158 wxASSERT_MSG( pItem != NULL, "can't append NULL item to the menu" );
159#if wxUSE_ACCEL
160 UpdateAccel(pItem);
161#endif // wxUSE_ACCEL
e9576ca5 162
519cb848
SC
163 if ( pItem->IsSeparator() )
164 {
e7549107
SC
165 if ( pos == (size_t)-1 )
166 {
167 MacAppendMenu(m_hMenu, "\p-");
168 }
169 else
170 {
171 MacInsertMenuItem(m_hMenu, "\p-" , pos);
172 }
519cb848
SC
173 }
174 else
175 {
176 wxMenu *pSubMenu = pItem->GetSubMenu() ;
177 if ( pSubMenu != NULL )
178 {
179 Str255 label;
e7549107
SC
180 wxASSERT_MSG( pSubMenu->m_hMenu != NULL , "invalid submenu added");
181 pSubMenu->m_menuParent = this ;
2f1ae414 182 wxMenuItem::MacBuildMenuString( label , NULL , NULL , pItem->GetText() ,false);
519cb848 183
e7549107 184 if (wxMenuBar::MacGetInstalledMenuBar() == m_menuBar)
519cb848 185 {
72055702 186 ::InsertMenu( pSubMenu->m_hMenu , -1 ) ;
519cb848
SC
187 }
188
e7549107
SC
189 if ( pos == (size_t)-1 )
190 {
2f1ae414 191 UMAAppendSubMenuItem(m_hMenu, label, pSubMenu->m_macMenuId);
e7549107
SC
192 }
193 else
194 {
2f1ae414 195 UMAInsertSubMenuItem(m_hMenu, label , pos, pSubMenu->m_macMenuId);
e7549107 196 }
519cb848
SC
197 }
198 else
199 {
200 Str255 label ;
2f1ae414
SC
201 UInt8 modifiers ;
202 SInt16 key ;
203 wxMenuItem::MacBuildMenuString( label, &key , &modifiers , pItem->GetText(), pItem->GetId() == wxApp::s_macAboutMenuItemId);
519cb848
SC
204 if ( label[0] == 0 )
205 {
206 // we cannot add empty menus on mac
207 label[0] = 1 ;
208 label[1] = ' ' ;
209 }
e7549107
SC
210 if ( pos == (size_t)-1 )
211 {
2f1ae414 212 UMAAppendMenuItem(m_hMenu, label,key,modifiers);
e7549107
SC
213 }
214 else
215 {
2f1ae414 216 UMAInsertMenuItem(m_hMenu, label , pos,key,modifiers);
e7549107 217 }
519cb848
SC
218 if ( pItem->GetId() == idMenuTitle )
219 {
e7549107
SC
220 if ( pos == (size_t)-1 )
221 {
2f1ae414 222 UMADisableMenuItem( m_hMenu , CountMenuItems( m_hMenu ) ) ;
e7549107
SC
223 }
224 else
225 {
226 UMADisableMenuItem( m_hMenu , pos + 1 ) ;
227 }
519cb848
SC
228 }
229 }
230 }
e7549107
SC
231 // if we're already attached to the menubar, we must update it
232 if ( IsAttached() )
233 {
234 m_menuBar->Refresh();
235 }
236 return TRUE ;
e9576ca5
SC
237}
238
e7549107 239bool wxMenu::DoAppend(wxMenuItem *item)
e9576ca5 240{
e7549107 241 return wxMenuBase::DoAppend(item) && DoInsertOrAppend(item);
e9576ca5
SC
242}
243
e7549107 244bool wxMenu::DoInsert(size_t pos, wxMenuItem *item)
e9576ca5 245{
e7549107 246 return wxMenuBase::DoInsert(pos, item) && DoInsertOrAppend(item, pos);
e9576ca5
SC
247}
248
e7549107 249wxMenuItem *wxMenu::DoRemove(wxMenuItem *item)
e9576ca5 250{
e7549107
SC
251 // we need to find the items position in the child list
252 size_t pos;
253 wxMenuItemList::Node *node = GetMenuItems().GetFirst();
254 for ( pos = 0; node; pos++ )
255 {
256 if ( node->GetData() == item )
257 break;
e9576ca5 258
e7549107 259 node = node->GetNext();
e9576ca5
SC
260 }
261
e7549107
SC
262 // DoRemove() (unlike Remove) can only be called for existing item!
263 wxCHECK_MSG( node, NULL, wxT("bug in wxMenu::Remove logic") );
519cb848 264
e7549107
SC
265#if wxUSE_ACCEL
266 // remove the corresponding accel from the accel table
267 int n = FindAccel(item->GetId());
268 if ( n != wxNOT_FOUND )
269 {
270 delete m_accels[n];
519cb848 271
3ef585df 272 m_accels.RemoveAt(n);
e7549107
SC
273 }
274 //else: this item doesn't have an accel, nothing to do
275#endif // wxUSE_ACCEL
e9576ca5 276
e7549107 277 ::DeleteMenuItem( m_hMenu , pos + 1);
e9576ca5 278
e7549107
SC
279 if ( IsAttached() )
280 {
281 // otherwise, the chane won't be visible
282 m_menuBar->Refresh();
283 }
e9576ca5 284
e7549107
SC
285 // and from internal data structures
286 return wxMenuBase::DoRemove(item);
e9576ca5
SC
287}
288
e7549107
SC
289// ---------------------------------------------------------------------------
290// accelerator helpers
291// ---------------------------------------------------------------------------
e9576ca5 292
e7549107 293#if wxUSE_ACCEL
e9576ca5 294
e7549107
SC
295// create the wxAcceleratorEntries for our accels and put them into provided
296// array - return the number of accels we have
297size_t wxMenu::CopyAccels(wxAcceleratorEntry *accels) const
e9576ca5 298{
e7549107
SC
299 size_t count = GetAccelCount();
300 for ( size_t n = 0; n < count; n++ )
301 {
302 *accels++ = *m_accels[n];
303 }
e9576ca5 304
e7549107 305 return count;
e9576ca5
SC
306}
307
e7549107 308#endif // wxUSE_ACCEL
e9576ca5
SC
309
310void wxMenu::SetTitle(const wxString& label)
311{
519cb848 312 Str255 title ;
e9576ca5 313 m_title = label ;
2f1ae414 314 wxMenuItem::MacBuildMenuString( title, NULL , NULL , label , false );
e7549107 315 UMASetMenuTitle( m_hMenu , title ) ;
e9576ca5 316}
e7549107 317bool wxMenu::ProcessCommand(wxCommandEvent & event)
e9576ca5
SC
318{
319 bool processed = FALSE;
320
e7549107 321#if WXWIN_COMPATIBILITY
e9576ca5
SC
322 // Try a callback
323 if (m_callback)
324 {
e7549107
SC
325 (void)(*(m_callback))(*this, event);
326 processed = TRUE;
e9576ca5 327 }
e7549107 328#endif WXWIN_COMPATIBILITY
e9576ca5
SC
329
330 // Try the menu's event handler
331 if ( !processed && GetEventHandler())
332 {
e7549107 333 processed = GetEventHandler()->ProcessEvent(event);
e9576ca5 334 }
519cb848 335
e7549107
SC
336 // Try the window the menu was popped up from (and up through the
337 // hierarchy)
338 wxWindow *win = GetInvokingWindow();
339 if ( !processed && win )
340 processed = win->GetEventHandler()->ProcessEvent(event);
341
342 return processed;
343}
344
345
346// ---------------------------------------------------------------------------
347// other
348// ---------------------------------------------------------------------------
349
e7549107
SC
350wxWindow *wxMenu::GetWindow() const
351{
352 if ( m_invokingWindow != NULL )
353 return m_invokingWindow;
354 else if ( m_menuBar != NULL)
03e11df5 355 return (wxWindow *) m_menuBar->GetFrame();
e7549107
SC
356
357 return NULL;
358}
519cb848 359
519cb848
SC
360// helper functions returning the mac menu position for a certain item, note that this is
361// mac-wise 1 - based, i.e. the first item has index 1 whereas on MSWin it has pos 0
362
363int wxMenu::MacGetIndexFromId( int id )
364{
e7549107
SC
365 size_t pos;
366 wxMenuItemList::Node *node = GetMenuItems().GetFirst();
367 for ( pos = 0; node; pos++ )
519cb848 368 {
e7549107
SC
369 if ( node->GetData()->GetId() == id )
370 break;
519cb848 371
e7549107
SC
372 node = node->GetNext();
373 }
374
519cb848
SC
375 if (!node)
376 return 0;
377
378 return pos + 1 ;
379}
380
381int wxMenu::MacGetIndexFromItem( wxMenuItem *pItem )
382{
e7549107
SC
383 size_t pos;
384 wxMenuItemList::Node *node = GetMenuItems().GetFirst();
385 for ( pos = 0; node; pos++ )
519cb848 386 {
e7549107
SC
387 if ( node->GetData() == pItem )
388 break;
389
390 node = node->GetNext();
519cb848
SC
391 }
392
393 if (!node)
394 return 0;
395
396 return pos + 1 ;
397}
398
399void wxMenu::MacEnableMenu( bool bDoEnable )
400{
519cb848 401 if ( bDoEnable )
e7549107 402 UMAEnableMenuItem( m_hMenu , 0 ) ;
519cb848 403 else
e7549107 404 UMADisableMenuItem( m_hMenu , 0 ) ;
519cb848
SC
405
406 ::DrawMenuBar() ;
407}
408
409bool wxMenu::MacMenuSelect( wxEvtHandler* handler, long when , int macMenuId, int macMenuItemNum )
410{
411 int pos;
412 wxNode *node;
413
414 if ( m_macMenuId == macMenuId )
415 {
e7549107 416 node = GetMenuItems().Nth(macMenuItemNum-1);
519cb848
SC
417 if (node)
418 {
419 wxMenuItem *pItem = (wxMenuItem*)node->Data();
2f1ae414
SC
420
421 if (pItem->IsCheckable())
422 pItem->Check(! pItem->IsChecked());
423
519cb848
SC
424 wxCommandEvent event(wxEVT_COMMAND_MENU_SELECTED, pItem->GetId());
425 event.m_timeStamp = when;
426 event.SetEventObject(handler);
e7549107 427 event.SetInt( pItem->GetId() );
51abe921
SC
428 {
429 bool processed = false ;
430
431#if WXWIN_COMPATIBILITY
432 // Try a callback
433 if (m_callback)
434 {
435 (void) (*(m_callback)) (*this, event);
436 processed = TRUE;
437 }
438#endif
439 // Try the menu's event handler
440 if ( !processed && handler)
441 {
442 processed = handler->ProcessEvent(event);
443 }
444
445 // Try the window the menu was popped up from (and up
446 // through the hierarchy)
447 if ( !processed && GetInvokingWindow())
448 processed = GetInvokingWindow()->GetEventHandler()->ProcessEvent(event);
449 }
519cb848
SC
450 return true ;
451 }
452 }
f5c6eb5c 453#ifndef __DARWIN__
519cb848
SC
454 else if ( macMenuId == kHMHelpMenuID )
455 {
456 int menuItem = formerHelpMenuItems ;
e7549107 457 for (pos = 0, node = GetMenuItems().First(); node; node = node->Next(), pos++)
519cb848
SC
458 {
459 wxMenuItem * pItem = (wxMenuItem *) node->Data() ;
460
461 wxMenu *pSubMenu = pItem->GetSubMenu() ;
462 if ( pSubMenu != NULL )
463 {
464 }
465 else
466 {
467 if ( pItem->GetId() != wxApp::s_macAboutMenuItemId )
468 ++menuItem ;
469
470 if ( menuItem == macMenuItemNum )
471 {
472 wxCommandEvent event(wxEVT_COMMAND_MENU_SELECTED, pItem->GetId());
473 event.m_timeStamp = when;
474 event.SetEventObject(handler);
e7549107 475 event.SetInt( pItem->GetId() );
51abe921
SC
476 {
477 bool processed = false ;
478#if WXWIN_COMPATIBILITY
479 // Try a callback
480 if (m_callback)
481 {
482 (void) (*(m_callback)) (*this, event);
483 processed = TRUE;
484 }
485#endif
486 // Try the menu's event handler
487 if ( !processed && handler)
488 {
489 processed = handler->ProcessEvent(event);
490 }
491
492 // Try the window the menu was popped up from (and up
493 // through the hierarchy)
494 if ( !processed && GetInvokingWindow())
495 processed = GetInvokingWindow()->GetEventHandler()->ProcessEvent(event);
496 }
519cb848
SC
497 return true ;
498 }
499 }
500 }
501 }
f5c6eb5c 502#endif // __DARWIN__
519cb848 503
e7549107 504 for (pos = 0, node = GetMenuItems().First(); node; node = node->Next(), pos++)
519cb848 505 {
e7549107 506 wxMenuItem * pItem = (wxMenuItem *) node->Data() ;
519cb848 507
e7549107 508 wxMenu *pSubMenu = pItem->GetSubMenu() ;
519cb848
SC
509 if ( pSubMenu != NULL )
510 {
511 if ( pSubMenu->MacMenuSelect( handler , when , macMenuId , macMenuItemNum ) )
512 return true ;
513 }
514 }
515
516 return false ;
e9576ca5
SC
517}
518
519// Menu Bar
519cb848
SC
520
521/*
522
523Mac Implementation note :
524
525The Mac has only one global menubar, so we attempt to install the currently
526active menubar from a frame, we currently don't take into account mdi-frames
527which would ask for menu-merging
528
529Secondly there is no mac api for changing a menubar that is not the current
530menubar, so we have to wait for preparing the actual menubar until the
531wxMenubar is to be used
532
533We can in subsequent versions use MacInstallMenuBar to provide some sort of
534auto-merge for MDI in case this will be necessary
535
536*/
537
538wxMenuBar* wxMenuBar::s_macInstalledMenuBar = NULL ;
539
e7549107 540void wxMenuBar::Init()
e9576ca5
SC
541{
542 m_eventHandler = this;
e9576ca5 543 m_menuBarFrame = NULL;
e9576ca5
SC
544}
545
51abe921
SC
546wxMenuBar::wxMenuBar()
547{
548 Init();
549}
550
551wxMenuBar::wxMenuBar( long WXUNUSED(style) )
552{
553 Init();
554}
555
e7549107
SC
556
557wxMenuBar::wxMenuBar(int count, wxMenu *menus[], const wxString titles[])
e9576ca5 558{
e7549107
SC
559 Init();
560
561 m_titles.Alloc(count);
562
563 for ( int i = 0; i < count; i++ )
564 {
565 m_menus.Append(menus[i]);
566 m_titles.Add(titles[i]);
567
568 menus[i]->Attach(this);
569 }
e9576ca5
SC
570}
571
572wxMenuBar::~wxMenuBar()
573{
519cb848
SC
574 if (s_macInstalledMenuBar == this)
575 {
576 ::ClearMenuBar();
577 s_macInstalledMenuBar = NULL;
578 }
579
e7549107
SC
580}
581
582void wxMenuBar::Refresh()
583{
584 wxCHECK_RET( IsAttached(), wxT("can't refresh unatteched menubar") );
e9576ca5 585
e7549107 586 DrawMenuBar();
e9576ca5
SC
587}
588
51abe921
SC
589#if wxUSE_ACCEL
590
591void wxMenuBar::RebuildAccelTable()
592{
593 // merge the accelerators of all menus into one accel table
594 size_t nAccelCount = 0;
595 size_t i, count = GetMenuCount();
596 for ( i = 0; i < count; i++ )
597 {
598 nAccelCount += m_menus[i]->GetAccelCount();
599 }
600
601 if ( nAccelCount )
602 {
603 wxAcceleratorEntry *accelEntries = new wxAcceleratorEntry[nAccelCount];
604
605 nAccelCount = 0;
606 for ( i = 0; i < count; i++ )
607 {
608 nAccelCount += m_menus[i]->CopyAccels(&accelEntries[nAccelCount]);
609 }
610
611 m_accelTable = wxAcceleratorTable(nAccelCount, accelEntries);
612
613 delete [] accelEntries;
614 }
615}
616
617#endif // wxUSE_ACCEL
618
619
519cb848
SC
620void wxMenuBar::MacInstallMenuBar()
621{
41f38f4d
SC
622 if ( s_macInstalledMenuBar == this )
623 return ;
624
519cb848
SC
625 Handle menubar = ::GetNewMBar( kwxMacMenuBarResource ) ;
626 wxString message ;
627 wxCHECK_RET( menubar != NULL, "can't read MBAR resource" );
628 ::SetMenuBar( menubar ) ;
629 ::DisposeHandle( menubar ) ;
630
631 MenuHandle menu = ::GetMenuHandle( kwxMacAppleMenuId ) ;
632 ::AppendResMenu(menu, 'DRVR');
633
e7549107 634 for (int i = 0; i < m_menus.GetCount(); i++)
519cb848
SC
635 {
636 Str255 label;
637 wxNode *node;
638 wxMenuItem *item;
639 int pos ;
640 wxMenu* menu = m_menus[i] , *subMenu = NULL ;
641
2f1ae414
SC
642#if !TARGET_CARBON
643 /* the help menu does not exist in CARBON anymore */
8208e181 644 if( m_titles[i] == "?" || m_titles[i] == "&?" || m_titles[i] == wxApp::s_macHelpMenuTitleName )
519cb848
SC
645 {
646 MenuHandle mh = NULL ;
647 if ( HMGetHelpMenuHandle( &mh ) != noErr )
648 {
649 continue ;
650 }
651 if ( formerHelpMenuItems == 0 )
652 {
653 if( mh )
654 formerHelpMenuItems = CountMenuItems( mh ) ;
655 }
656
2f1ae414
SC
657 for (pos = 0 , node = menu->GetMenuItems().First(); node; node = node->Next(), pos++)
658 {
519cb848
SC
659 item = (wxMenuItem *)node->Data();
660 subMenu = item->GetSubMenu() ;
661 if (subMenu)
662 {
663 // we don't support hierarchical menus in the help menu yet
664 }
665 else
666 {
8208e181 667 if ( item->IsSeparator() )
519cb848 668 {
8208e181 669 if ( mh )
2f1ae414 670 UMAAppendMenuItem(mh, "\p-" );
519cb848 671 }
519cb848
SC
672 else
673 {
8208e181 674 Str255 label ;
2f1ae414
SC
675 UInt8 modifiers ;
676 SInt16 key ;
677 wxMenuItem::MacBuildMenuString( label, &key , &modifiers , item->GetText(), item->GetId() != wxApp::s_macAboutMenuItemId); // no shortcut in about menu
8208e181
SC
678 if ( label[0] == 0 )
679 {
680 // we cannot add empty menus on mac
681 label[0] = 1 ;
682 label[1] = ' ' ;
683 }
684 if ( item->GetId() == wxApp::s_macAboutMenuItemId )
685 {
72055702 686 ::SetMenuItemText( GetMenuHandle( kwxMacAppleMenuId ) , 1 , label );
2f1ae414 687 UMAEnableMenuItem( GetMenuHandle( kwxMacAppleMenuId ) , 1 );
8208e181
SC
688 }
689 else
690 {
691 if ( mh )
2f1ae414 692 UMAAppendMenuItem(mh, label , key , modifiers );
8208e181 693 }
519cb848
SC
694 }
695 }
696 }
697 }
5b781a67
SC
698#else
699 if( m_titles[i] == "?" || m_titles[i] == "&?" || m_titles[i] == wxApp::s_macHelpMenuTitleName )
700 {
9673f535
SC
701 wxMenuItem::MacBuildMenuString( label, NULL , NULL , m_titles[i] , false );
702 UMASetMenuTitle( menu->GetHMenu() , label ) ;
703
704 wxArrayPtrVoid submenus ;
5b781a67
SC
705
706 for (pos = 0 , node = menu->GetMenuItems().First(); node; node = node->Next(), pos++)
707 {
9673f535
SC
708 item = (wxMenuItem *)node->Data();
709 subMenu = item->GetSubMenu() ;
710 if (subMenu)
711 {
712 submenus.Add(subMenu) ;
713 }
714 else
715 {
716 if ( item->GetId() == wxApp::s_macAboutMenuItemId )
717 {
718 Str255 label ;
719 UInt8 modifiers ;
720 SInt16 key ;
721 wxMenuItem::MacBuildMenuString( label, &key , &modifiers , item->GetText(), item->GetId() != wxApp::s_macAboutMenuItemId); // no shortcut in about menu
722 ::SetMenuItemText( GetMenuHandle( kwxMacAppleMenuId ) , 1 , label );
723 UMAEnableMenuItem( GetMenuHandle( kwxMacAppleMenuId ) , 1 );
724 }
725 }
726 }
727 ::InsertMenu(m_menus[i]->GetHMenu(), 0);
728 for ( int i = 0 ; i < submenus.GetCount() ; ++i )
729 {
730 wxMenu* submenu = (wxMenu*) submenus[i] ;
731 wxNode *subnode;
732 wxMenuItem *subitem;
733 int subpos ;
734 for ( subpos = 0 , subnode = submenu->GetMenuItems().First(); subnode; subnode = subnode->Next(), subpos++)
735 {
736 subitem = (wxMenuItem *)subnode->Data();
737 wxMenu* itsSubMenu = subitem->GetSubMenu() ;
738 if (itsSubMenu)
739 {
740 submenus.Add(itsSubMenu) ;
741 }
742 }
743 ::InsertMenu( submenu->GetHMenu() , -1 ) ;
744 }
5b781a67 745 }
2f1ae414 746#endif
5b781a67 747 else
519cb848 748 {
2f1ae414 749 wxMenuItem::MacBuildMenuString( label, NULL , NULL , m_titles[i] , false );
e7549107 750 UMASetMenuTitle( menu->GetHMenu() , label ) ;
9673f535
SC
751 wxArrayPtrVoid submenus ;
752
2f1ae414
SC
753 for (pos = 0, node = menu->GetMenuItems().First(); node; node = node->Next(), pos++)
754 {
519cb848
SC
755 item = (wxMenuItem *)node->Data();
756 subMenu = item->GetSubMenu() ;
757 if (subMenu)
758 {
9673f535 759 submenus.Add(subMenu) ;
519cb848
SC
760 }
761 }
72055702 762 ::InsertMenu(m_menus[i]->GetHMenu(), 0);
9673f535
SC
763 for ( int i = 0 ; i < submenus.GetCount() ; ++i )
764 {
765 wxMenu* submenu = (wxMenu*) submenus[i] ;
766 wxNode *subnode;
767 wxMenuItem *subitem;
768 int subpos ;
769 for ( subpos = 0 , subnode = submenu->GetMenuItems().First(); subnode; subnode = subnode->Next(), subpos++)
770 {
771 subitem = (wxMenuItem *)subnode->Data();
772 wxMenu* itsSubMenu = subitem->GetSubMenu() ;
773 if (itsSubMenu)
774 {
775 submenus.Add(itsSubMenu) ;
776 }
777 }
778 ::InsertMenu( submenu->GetHMenu() , -1 ) ;
779 }
519cb848
SC
780 }
781 }
72055702 782 ::DrawMenuBar() ;
519cb848
SC
783
784 s_macInstalledMenuBar = this;
785}
786
e7549107 787void wxMenuBar::EnableTop(size_t pos, bool enable)
e9576ca5 788{
e7549107
SC
789 wxCHECK_RET( IsAttached(), wxT("doesn't work with unattached menubars") );
790 m_menus[pos]->MacEnableMenu( enable ) ;
791 Refresh();
e9576ca5
SC
792}
793
e7549107 794void wxMenuBar::SetLabelTop(size_t pos, const wxString& label)
e9576ca5 795{
e7549107 796 wxCHECK_RET( pos < GetMenuCount(), wxT("invalid menu index") );
e9576ca5 797
e7549107 798 m_titles[pos] = label;
e9576ca5 799
e7549107
SC
800 if ( !IsAttached() )
801 {
e9576ca5 802 return;
e7549107 803 }
e9576ca5 804
519cb848 805 m_menus[pos]->SetTitle( label ) ;
e7549107 806 if (wxMenuBar::s_macInstalledMenuBar == this) // are we currently installed ?
519cb848 807 {
e7549107 808 ::SetMenuBar( GetMenuBar() ) ;
519cb848 809 ::InvalMenuBar() ;
519cb848 810 }
e9576ca5
SC
811}
812
e7549107 813wxString wxMenuBar::GetLabelTop(size_t pos) const
e9576ca5 814{
e7549107
SC
815 wxCHECK_MSG( pos < GetMenuCount(), wxEmptyString,
816 wxT("invalid menu index in wxMenuBar::GetLabelTop") );
519cb848 817
e7549107 818 return m_titles[pos];
e9576ca5
SC
819}
820
e7549107 821int wxMenuBar::FindMenu(const wxString& title)
e9576ca5 822{
e7549107 823 wxString menuTitle = wxStripMenuCodes(title);
e9576ca5 824
e7549107
SC
825 size_t count = GetMenuCount();
826 for ( size_t i = 0; i < count; i++ )
e9576ca5 827 {
e7549107
SC
828 wxString title = wxStripMenuCodes(m_titles[i]);
829 if ( menuTitle == title )
830 return i;
e9576ca5 831 }
e9576ca5 832
e7549107 833 return wxNOT_FOUND;
e9576ca5 834
e9576ca5
SC
835}
836
e7549107
SC
837
838// ---------------------------------------------------------------------------
839// wxMenuBar construction
840// ---------------------------------------------------------------------------
841
842// ---------------------------------------------------------------------------
843// wxMenuBar construction
844// ---------------------------------------------------------------------------
845
846wxMenu *wxMenuBar::Replace(size_t pos, wxMenu *menu, const wxString& title)
e9576ca5 847{
e7549107
SC
848 wxMenu *menuOld = wxMenuBarBase::Replace(pos, menu, title);
849 if ( !menuOld )
850 return FALSE;
851 m_titles[pos] = title;
e9576ca5 852
e7549107 853 if ( IsAttached() )
e9576ca5 854 {
e7549107
SC
855 if (s_macInstalledMenuBar == this)
856 {
72055702 857 ::DeleteMenu( menuOld->MacGetMenuId() /* m_menus[pos]->MacGetMenuId() */ ) ;
e7549107
SC
858 {
859 Str255 label;
2f1ae414 860 wxMenuItem::MacBuildMenuString( label, NULL , NULL , title , false );
e7549107
SC
861 UMASetMenuTitle( menu->GetHMenu() , label ) ;
862 if ( pos == m_menus.GetCount() - 1)
863 {
72055702 864 ::InsertMenu( menu->GetHMenu() , 0 ) ;
e7549107
SC
865 }
866 else
867 {
72055702 868 ::InsertMenu( menu->GetHMenu() , m_menus[pos+1]->MacGetMenuId() ) ;
e7549107
SC
869 }
870 }
871 }
e9576ca5 872
e9576ca5 873
e7549107
SC
874#if wxUSE_ACCEL
875 if ( menuOld->HasAccels() || menu->HasAccels() )
876 {
877 // need to rebuild accell table
878 RebuildAccelTable();
879 }
880#endif // wxUSE_ACCEL
e9576ca5 881
e7549107 882 Refresh();
e9576ca5 883 }
e9576ca5 884
e7549107 885 return menuOld;
e9576ca5
SC
886}
887
e7549107 888bool wxMenuBar::Insert(size_t pos, wxMenu *menu, const wxString& title)
e9576ca5 889{
e7549107
SC
890 if ( !wxMenuBarBase::Insert(pos, menu, title) )
891 return FALSE;
e9576ca5 892
e7549107 893 m_titles.Insert(title, pos);
e9576ca5 894
e7549107
SC
895 menu->Attach(this);
896
897 if ( IsAttached() )
e9576ca5 898 {
e7549107
SC
899 if ( pos == (size_t) -1 )
900 {
901 ::InsertMenu( menu->GetHMenu() , 0 ) ;
902 }
903 else
904 {
905 ::InsertMenu( menu->GetHMenu() , m_menus[pos+1]->MacGetMenuId() ) ;
906 }
907
908#if wxUSE_ACCEL
909 if ( menu->HasAccels() )
e9576ca5 910 {
e7549107
SC
911 // need to rebuild accell table
912 RebuildAccelTable();
e9576ca5 913 }
e7549107 914#endif // wxUSE_ACCEL
e9576ca5 915
e7549107 916 Refresh();
e9576ca5 917 }
e7549107
SC
918
919 return TRUE;
e9576ca5
SC
920}
921
519cb848
SC
922void wxMenuBar::MacMenuSelect(wxEvtHandler* handler, long when , int macMenuId, int macMenuItemNum)
923{
924 // first scan fast for direct commands, i.e. menus which have these commands directly in their own list
925
926 if ( macMenuId == kwxMacAppleMenuId && macMenuItemNum == 1 )
927 {
928 wxCommandEvent event(wxEVT_COMMAND_MENU_SELECTED, wxApp::s_macAboutMenuItemId );
929 event.m_timeStamp = when;
930 event.SetEventObject(handler);
931 event.SetInt( wxApp::s_macAboutMenuItemId );
932 handler->ProcessEvent(event);
933 }
934 else
935 {
e7549107 936 for (int i = 0; i < m_menus.GetCount() ; i++)
519cb848 937 {
03e11df5 938 if ( m_menus[i]->MacGetMenuId() == macMenuId
f5c6eb5c 939#ifndef __DARWIN__
03e11df5 940 ||
8208e181 941 ( macMenuId == kHMHelpMenuID && ( m_titles[i] == "?" || m_titles[i] == "&?" || m_titles[i] == wxApp::s_macHelpMenuTitleName ) )
03e11df5 942#endif
519cb848
SC
943 )
944 {
945 if ( m_menus[i]->MacMenuSelect( handler , when , macMenuId , macMenuItemNum ) )
946 return ;
947 else
948 {
949 //TODO flag this as an error since it must contain the item
950 return ;
951 }
952 }
953 }
954
e7549107 955 for (int i = 0; i < m_menus.GetCount(); i++)
519cb848
SC
956 {
957 if ( m_menus[i]->MacMenuSelect( handler , when , macMenuId , macMenuItemNum ) )
958 {
959 break ;
960 }
51abe921 961 }
519cb848
SC
962 }
963}
e9576ca5 964
51abe921
SC
965wxMenu *wxMenuBar::Remove(size_t pos)
966{
967 wxMenu *menu = wxMenuBarBase::Remove(pos);
968 if ( !menu )
969 return NULL;
970
971 if ( IsAttached() )
972 {
973 if (s_macInstalledMenuBar == this)
974 {
975 ::DeleteMenu( menu->MacGetMenuId() /* m_menus[pos]->MacGetMenuId() */ ) ;
976 }
977
978 menu->Detach();
979
980#if wxUSE_ACCEL
981 if ( menu->HasAccels() )
982 {
983 // need to rebuild accell table
984 RebuildAccelTable();
985 }
986#endif // wxUSE_ACCEL
987
988 Refresh();
989 }
990
991 m_titles.Remove(pos);
992
993 return menu;
994}
995
996bool wxMenuBar::Append(wxMenu *menu, const wxString& title)
997{
998 WXHMENU submenu = menu ? menu->GetHMenu() : 0;
999 wxCHECK_MSG( submenu, FALSE, wxT("can't append invalid menu to menubar") );
1000
1001 if ( !wxMenuBarBase::Append(menu, title) )
1002 return FALSE;
1003
51abe921
SC
1004 m_titles.Add(title);
1005
1006 if ( IsAttached() )
1007 {
1008 if (s_macInstalledMenuBar == this)
1009 {
1010 ::InsertMenu( menu->GetHMenu() , 0 ) ;
1011 }
1012
1013#if wxUSE_ACCEL
1014 if ( menu->HasAccels() )
1015 {
1016 // need to rebuild accell table
1017 RebuildAccelTable();
1018 }
1019#endif // wxUSE_ACCEL
1020
1021 Refresh();
1022 }
1023
1024 return TRUE;
1025}
1026
90b959ae 1027void wxMenuBar::Detach()
2f1ae414 1028{
90b959ae
SC
1029 wxMenuBarBase::Detach() ;
1030}
2f1ae414 1031
90b959ae
SC
1032void wxMenuBar::Attach(wxFrame *frame)
1033{
1034 wxMenuBarBase::Attach( frame ) ;
2f1ae414
SC
1035
1036#if wxUSE_ACCEL
1037 RebuildAccelTable();
1038#endif // wxUSE_ACCEL
1039}
51abe921
SC
1040// ---------------------------------------------------------------------------
1041// wxMenuBar searching for menu items
1042// ---------------------------------------------------------------------------
1043
1044// Find the itemString in menuString, and return the item id or wxNOT_FOUND
1045int wxMenuBar::FindMenuItem(const wxString& menuString,
1046 const wxString& itemString) const
1047{
1048 wxString menuLabel = wxStripMenuCodes(menuString);
1049 size_t count = GetMenuCount();
1050 for ( size_t i = 0; i < count; i++ )
1051 {
1052 wxString title = wxStripMenuCodes(m_titles[i]);
1053 if ( menuString == title )
1054 return m_menus[i]->FindItem(itemString);
1055 }
1056
1057 return wxNOT_FOUND;
1058}
1059
1060wxMenuItem *wxMenuBar::FindItem(int id, wxMenu **itemMenu) const
1061{
1062 if ( itemMenu )
1063 *itemMenu = NULL;
1064
1065 wxMenuItem *item = NULL;
1066 size_t count = GetMenuCount();
1067 for ( size_t i = 0; !item && (i < count); i++ )
1068 {
1069 item = m_menus[i]->FindItem(id, itemMenu);
1070 }
1071
1072 return item;
1073}
1074
1075