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