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