]> git.saurik.com Git - wxWidgets.git/blame - src/mac/menu.cpp
take out key handling at control level, we'll remove that later on, if things are...
[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
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{
76a5e5d2
SC
91 if (MAC_WXHMENU(m_hMenu))
92 ::DisposeMenu(MAC_WXHMENU(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 {
76a5e5d2 167 MacAppendMenu(MAC_WXHMENU(m_hMenu), "\p-");
e7549107
SC
168 }
169 else
170 {
76a5e5d2 171 MacInsertMenuItem(MAC_WXHMENU(m_hMenu), "\p-" , pos);
e7549107 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 {
76a5e5d2 186 ::InsertMenu( MAC_WXHMENU( pSubMenu->m_hMenu ) , -1 ) ;
519cb848
SC
187 }
188
e7549107
SC
189 if ( pos == (size_t)-1 )
190 {
76a5e5d2 191 UMAAppendSubMenuItem(MAC_WXHMENU(m_hMenu), label, pSubMenu->m_macMenuId);
e7549107
SC
192 }
193 else
194 {
76a5e5d2 195 UMAInsertSubMenuItem(MAC_WXHMENU(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 {
76a5e5d2 212 UMAAppendMenuItem(MAC_WXHMENU(m_hMenu), label,key,modifiers);
e7549107
SC
213 }
214 else
215 {
76a5e5d2 216 UMAInsertMenuItem(MAC_WXHMENU(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 {
76a5e5d2 222 UMADisableMenuItem(MAC_WXHMENU(m_hMenu) , CountMenuItems(MAC_WXHMENU(m_hMenu) ) ) ;
e7549107
SC
223 }
224 else
225 {
76a5e5d2 226 UMADisableMenuItem(MAC_WXHMENU(m_hMenu) , pos + 1 ) ;
e7549107 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
76a5e5d2 277 ::DeleteMenuItem(MAC_WXHMENU(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 );
76a5e5d2 315 UMASetMenuTitle(MAC_WXHMENU(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 )
76a5e5d2 402 UMAEnableMenuItem(MAC_WXHMENU(m_hMenu) , 0 ) ;
519cb848 403 else
76a5e5d2 404 UMADisableMenuItem(MAC_WXHMENU(m_hMenu) , 0 ) ;
519cb848
SC
405
406 ::DrawMenuBar() ;
407}
408
409bool wxMenu::MacMenuSelect( wxEvtHandler* handler, long when , int macMenuId, int macMenuItemNum )
410{
8caf72d3
GD
411 int pos;
412 wxNode *node;
51abe921 413
8caf72d3
GD
414 if ( m_macMenuId == macMenuId )
415 {
416 node = GetMenuItems().Nth(macMenuItemNum-1);
417 if (node)
418 {
419 wxMenuItem *pItem = (wxMenuItem*)node->Data();
420
421 if (pItem->IsCheckable())
422 pItem->Check(! pItem->IsChecked());
423
424 wxCommandEvent event(wxEVT_COMMAND_MENU_SELECTED, pItem->GetId());
425 event.m_timeStamp = when;
426 event.SetEventObject(handler);
427 event.SetInt( pItem->GetId() );
428 {
429 bool processed = false ;
430
51abe921 431#if WXWIN_COMPATIBILITY
8caf72d3
GD
432 // Try a callback
433 if (m_callback)
434 {
435 (void) (*(m_callback)) (*this, event);
436 processed = TRUE;
437 }
51abe921 438#endif
8caf72d3
GD
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 }
450 return true ;
451 }
452 }
453 else if ( macMenuId == kHMHelpMenuID )
454 {
455 int menuItem = firstUserHelpMenuItem-1 ;
456 for (pos = 0, node = GetMenuItems().First(); node; node = node->Next(), pos++)
457 {
458 wxMenuItem * pItem = (wxMenuItem *) node->Data() ;
459
460 wxMenu *pSubMenu = pItem->GetSubMenu() ;
461 if ( pSubMenu != NULL )
462 {
463 }
464 else
465 {
466 if ( pItem->GetId() != wxApp::s_macAboutMenuItemId )
467 ++menuItem ;
468
469 if ( menuItem == macMenuItemNum )
470 {
471 wxCommandEvent event(wxEVT_COMMAND_MENU_SELECTED, pItem->GetId());
472 event.m_timeStamp = when;
473 event.SetEventObject(handler);
474 event.SetInt( pItem->GetId() );
475 {
476 bool processed = false ;
51abe921 477#if WXWIN_COMPATIBILITY
8caf72d3
GD
478 // Try a callback
479 if (m_callback)
480 {
481 (void) (*(m_callback)) (*this, event);
482 processed = TRUE;
483 }
51abe921 484#endif
8caf72d3
GD
485 // Try the menu's event handler
486 if ( !processed && handler)
487 {
488 processed = handler->ProcessEvent(event);
489 }
490
491 // Try the window the menu was popped up from (and up
492 // through the hierarchy)
493 if ( !processed && GetInvokingWindow())
494 processed = GetInvokingWindow()->GetEventHandler()->ProcessEvent(event);
495 }
496 return true ;
497 }
498 }
499 }
500 }
501
502 for (pos = 0, node = GetMenuItems().First(); node; node = node->Next(), pos++)
503 {
504 wxMenuItem * pItem = (wxMenuItem *) node->Data() ;
519cb848 505
8caf72d3
GD
506 wxMenu *pSubMenu = pItem->GetSubMenu() ;
507 if ( pSubMenu != NULL )
508 {
509 if ( pSubMenu->MacMenuSelect( handler , when , macMenuId , macMenuItemNum ) )
510 return true ;
511 }
512 }
513
514 return false ;
e9576ca5
SC
515}
516
517// Menu Bar
519cb848
SC
518
519/*
520
521Mac Implementation note :
522
523The Mac has only one global menubar, so we attempt to install the currently
524active menubar from a frame, we currently don't take into account mdi-frames
525which would ask for menu-merging
526
527Secondly there is no mac api for changing a menubar that is not the current
528menubar, so we have to wait for preparing the actual menubar until the
529wxMenubar is to be used
530
531We can in subsequent versions use MacInstallMenuBar to provide some sort of
532auto-merge for MDI in case this will be necessary
533
534*/
535
536wxMenuBar* wxMenuBar::s_macInstalledMenuBar = NULL ;
537
e7549107 538void wxMenuBar::Init()
e9576ca5
SC
539{
540 m_eventHandler = this;
e9576ca5 541 m_menuBarFrame = NULL;
e9576ca5
SC
542}
543
51abe921
SC
544wxMenuBar::wxMenuBar()
545{
546 Init();
547}
548
549wxMenuBar::wxMenuBar( long WXUNUSED(style) )
550{
551 Init();
552}
553
e7549107
SC
554
555wxMenuBar::wxMenuBar(int count, wxMenu *menus[], const wxString titles[])
e9576ca5 556{
e7549107
SC
557 Init();
558
559 m_titles.Alloc(count);
560
561 for ( int i = 0; i < count; i++ )
562 {
563 m_menus.Append(menus[i]);
564 m_titles.Add(titles[i]);
565
566 menus[i]->Attach(this);
567 }
e9576ca5
SC
568}
569
570wxMenuBar::~wxMenuBar()
571{
519cb848
SC
572 if (s_macInstalledMenuBar == this)
573 {
574 ::ClearMenuBar();
575 s_macInstalledMenuBar = NULL;
576 }
577
e7549107
SC
578}
579
6d6da89c 580void wxMenuBar::Refresh(bool WXUNUSED(eraseBackground), const wxRect *WXUNUSED(rect))
e7549107
SC
581{
582 wxCHECK_RET( IsAttached(), wxT("can't refresh unatteched menubar") );
e9576ca5 583
e7549107 584 DrawMenuBar();
e9576ca5
SC
585}
586
51abe921
SC
587#if wxUSE_ACCEL
588
589void wxMenuBar::RebuildAccelTable()
590{
591 // merge the accelerators of all menus into one accel table
592 size_t nAccelCount = 0;
593 size_t i, count = GetMenuCount();
594 for ( i = 0; i < count; i++ )
595 {
596 nAccelCount += m_menus[i]->GetAccelCount();
597 }
598
599 if ( nAccelCount )
600 {
601 wxAcceleratorEntry *accelEntries = new wxAcceleratorEntry[nAccelCount];
602
603 nAccelCount = 0;
604 for ( i = 0; i < count; i++ )
605 {
606 nAccelCount += m_menus[i]->CopyAccels(&accelEntries[nAccelCount]);
607 }
608
609 m_accelTable = wxAcceleratorTable(nAccelCount, accelEntries);
610
611 delete [] accelEntries;
612 }
613}
614
615#endif // wxUSE_ACCEL
2b8a6962 616
519cb848
SC
617void wxMenuBar::MacInstallMenuBar()
618{
2b8a6962
GD
619 if ( s_macInstalledMenuBar == this )
620 return ;
41f38f4d 621
d9e054bc
SC
622 wxStAppResource resload ;
623
2b8a6962
GD
624 Handle menubar = ::GetNewMBar( kwxMacMenuBarResource ) ;
625 wxString message ;
626 wxCHECK_RET( menubar != NULL, "can't read MBAR resource" );
627 ::SetMenuBar( menubar ) ;
a3590de1
SC
628#if TARGET_API_MAC_CARBON
629 ::DisposeMenuBar( menubar ) ;
630#else
2b8a6962 631 ::DisposeHandle( menubar ) ;
a3590de1 632#endif
519cb848 633
a3590de1 634#if TARGET_API_MAC_OS8
2b8a6962 635 MenuHandle menu = ::GetMenuHandle( kwxMacAppleMenuId ) ;
d9e054bc
SC
636 if ( CountMenuItems( menu ) == 2 )
637 {
2b8a6962
GD
638 ::AppendResMenu(menu, 'DRVR');
639 }
a3590de1 640#endif
519cb848 641
2b8a6962 642 for (size_t i = 0; i < m_menus.GetCount(); i++)
519cb848 643 {
2b8a6962
GD
644 Str255 label;
645 wxNode *node;
646 wxMenuItem *item;
647 int pos ;
519cb848
SC
648 wxMenu* menu = m_menus[i] , *subMenu = NULL ;
649
8208e181 650 if( m_titles[i] == "?" || m_titles[i] == "&?" || m_titles[i] == wxApp::s_macHelpMenuTitleName )
519cb848
SC
651 {
652 MenuHandle mh = NULL ;
b03e4fcd
SC
653 if ( UMAGetHelpMenu( &mh , &firstUserHelpMenuItem) != noErr )
654 {
655 continue ;
656 }
a3590de1
SC
657
658 for ( int i = CountMenuItems( mh ) ; i >= firstUserHelpMenuItem ; --i )
659 {
660 DeleteMenuItem( mh , i ) ;
661 }
519cb848 662
2f1ae414
SC
663 for (pos = 0 , node = menu->GetMenuItems().First(); node; node = node->Next(), pos++)
664 {
519cb848
SC
665 item = (wxMenuItem *)node->Data();
666 subMenu = item->GetSubMenu() ;
667 if (subMenu)
668 {
669 // we don't support hierarchical menus in the help menu yet
670 }
671 else
672 {
8208e181 673 if ( item->IsSeparator() )
519cb848 674 {
8208e181 675 if ( mh )
5bc0790f 676 MacAppendMenu(mh, "\p-" );
519cb848 677 }
519cb848
SC
678 else
679 {
8208e181 680 Str255 label ;
2f1ae414
SC
681 UInt8 modifiers ;
682 SInt16 key ;
683 wxMenuItem::MacBuildMenuString( label, &key , &modifiers , item->GetText(), item->GetId() != wxApp::s_macAboutMenuItemId); // no shortcut in about menu
8208e181
SC
684 if ( label[0] == 0 )
685 {
686 // we cannot add empty menus on mac
687 label[0] = 1 ;
688 label[1] = ' ' ;
689 }
690 if ( item->GetId() == wxApp::s_macAboutMenuItemId )
691 {
72055702 692 ::SetMenuItemText( GetMenuHandle( kwxMacAppleMenuId ) , 1 , label );
2f1ae414 693 UMAEnableMenuItem( GetMenuHandle( kwxMacAppleMenuId ) , 1 );
8208e181
SC
694 }
695 else
696 {
697 if ( mh )
2f1ae414 698 UMAAppendMenuItem(mh, label , key , modifiers );
8208e181 699 }
519cb848
SC
700 }
701 }
702 }
703 }
5b781a67 704 else
519cb848 705 {
2f1ae414 706 wxMenuItem::MacBuildMenuString( label, NULL , NULL , m_titles[i] , false );
76a5e5d2 707 UMASetMenuTitle( MAC_WXHMENU(menu->GetHMenu()) , label ) ;
9673f535
SC
708 wxArrayPtrVoid submenus ;
709
2f1ae414
SC
710 for (pos = 0, node = menu->GetMenuItems().First(); node; node = node->Next(), pos++)
711 {
519cb848
SC
712 item = (wxMenuItem *)node->Data();
713 subMenu = item->GetSubMenu() ;
714 if (subMenu)
715 {
9673f535 716 submenus.Add(subMenu) ;
519cb848
SC
717 }
718 }
76a5e5d2 719 ::InsertMenu(MAC_WXHMENU(m_menus[i]->GetHMenu()), 0);
2b8a6962 720 for ( size_t i = 0 ; i < submenus.GetCount() ; ++i )
9673f535
SC
721 {
722 wxMenu* submenu = (wxMenu*) submenus[i] ;
723 wxNode *subnode;
724 wxMenuItem *subitem;
725 int subpos ;
726 for ( subpos = 0 , subnode = submenu->GetMenuItems().First(); subnode; subnode = subnode->Next(), subpos++)
727 {
728 subitem = (wxMenuItem *)subnode->Data();
729 wxMenu* itsSubMenu = subitem->GetSubMenu() ;
730 if (itsSubMenu)
731 {
732 submenus.Add(itsSubMenu) ;
733 }
734 }
76a5e5d2 735 ::InsertMenu( MAC_WXHMENU(submenu->GetHMenu()) , -1 ) ;
9673f535 736 }
519cb848
SC
737 }
738 }
72055702 739 ::DrawMenuBar() ;
519cb848
SC
740 s_macInstalledMenuBar = this;
741}
742
e7549107 743void wxMenuBar::EnableTop(size_t pos, bool enable)
e9576ca5 744{
e7549107
SC
745 wxCHECK_RET( IsAttached(), wxT("doesn't work with unattached menubars") );
746 m_menus[pos]->MacEnableMenu( enable ) ;
747 Refresh();
e9576ca5
SC
748}
749
e7549107 750void wxMenuBar::SetLabelTop(size_t pos, const wxString& label)
e9576ca5 751{
e7549107 752 wxCHECK_RET( pos < GetMenuCount(), wxT("invalid menu index") );
e9576ca5 753
e7549107 754 m_titles[pos] = label;
e9576ca5 755
e7549107
SC
756 if ( !IsAttached() )
757 {
e9576ca5 758 return;
e7549107 759 }
e9576ca5 760
519cb848 761 m_menus[pos]->SetTitle( label ) ;
e7549107 762 if (wxMenuBar::s_macInstalledMenuBar == this) // are we currently installed ?
519cb848 763 {
e7549107 764 ::SetMenuBar( GetMenuBar() ) ;
519cb848 765 ::InvalMenuBar() ;
519cb848 766 }
e9576ca5
SC
767}
768
e7549107 769wxString wxMenuBar::GetLabelTop(size_t pos) const
e9576ca5 770{
e7549107
SC
771 wxCHECK_MSG( pos < GetMenuCount(), wxEmptyString,
772 wxT("invalid menu index in wxMenuBar::GetLabelTop") );
519cb848 773
e7549107 774 return m_titles[pos];
e9576ca5
SC
775}
776
e7549107 777int wxMenuBar::FindMenu(const wxString& title)
e9576ca5 778{
e7549107 779 wxString menuTitle = wxStripMenuCodes(title);
e9576ca5 780
e7549107
SC
781 size_t count = GetMenuCount();
782 for ( size_t i = 0; i < count; i++ )
e9576ca5 783 {
e7549107
SC
784 wxString title = wxStripMenuCodes(m_titles[i]);
785 if ( menuTitle == title )
786 return i;
e9576ca5 787 }
e9576ca5 788
e7549107 789 return wxNOT_FOUND;
e9576ca5 790
e9576ca5
SC
791}
792
e7549107
SC
793
794// ---------------------------------------------------------------------------
795// wxMenuBar construction
796// ---------------------------------------------------------------------------
797
798// ---------------------------------------------------------------------------
799// wxMenuBar construction
800// ---------------------------------------------------------------------------
801
802wxMenu *wxMenuBar::Replace(size_t pos, wxMenu *menu, const wxString& title)
e9576ca5 803{
e7549107
SC
804 wxMenu *menuOld = wxMenuBarBase::Replace(pos, menu, title);
805 if ( !menuOld )
806 return FALSE;
807 m_titles[pos] = title;
e9576ca5 808
e7549107 809 if ( IsAttached() )
e9576ca5 810 {
e7549107
SC
811 if (s_macInstalledMenuBar == this)
812 {
72055702 813 ::DeleteMenu( menuOld->MacGetMenuId() /* m_menus[pos]->MacGetMenuId() */ ) ;
e7549107
SC
814 {
815 Str255 label;
2f1ae414 816 wxMenuItem::MacBuildMenuString( label, NULL , NULL , title , false );
76a5e5d2 817 UMASetMenuTitle( MAC_WXHMENU(menu->GetHMenu()) , label ) ;
e7549107
SC
818 if ( pos == m_menus.GetCount() - 1)
819 {
76a5e5d2 820 ::InsertMenu( MAC_WXHMENU(menu->GetHMenu()) , 0 ) ;
e7549107
SC
821 }
822 else
823 {
76a5e5d2 824 ::InsertMenu( MAC_WXHMENU(menu->GetHMenu()) , m_menus[pos+1]->MacGetMenuId() ) ;
e7549107
SC
825 }
826 }
827 }
e9576ca5 828
e9576ca5 829
e7549107
SC
830#if wxUSE_ACCEL
831 if ( menuOld->HasAccels() || menu->HasAccels() )
832 {
833 // need to rebuild accell table
834 RebuildAccelTable();
835 }
836#endif // wxUSE_ACCEL
e9576ca5 837
e7549107 838 Refresh();
e9576ca5 839 }
e9576ca5 840
e7549107 841 return menuOld;
e9576ca5
SC
842}
843
e7549107 844bool wxMenuBar::Insert(size_t pos, wxMenu *menu, const wxString& title)
e9576ca5 845{
e7549107
SC
846 if ( !wxMenuBarBase::Insert(pos, menu, title) )
847 return FALSE;
e9576ca5 848
e7549107 849 m_titles.Insert(title, pos);
e9576ca5 850
40325b26
SC
851 Str255 label ;
852 wxMenuItem::MacBuildMenuString( label, NULL , NULL , title , false );
853 UMASetMenuTitle( MAC_WXHMENU(menu->GetHMenu()) , label ) ;
e7549107
SC
854
855 if ( IsAttached() )
e9576ca5 856 {
40325b26 857 if ( pos == (size_t) -1 || pos + 1 == m_menus.GetCount() )
e7549107 858 {
76a5e5d2 859 ::InsertMenu( MAC_WXHMENU(menu->GetHMenu()) , 0 ) ;
e7549107
SC
860 }
861 else
862 {
76a5e5d2 863 ::InsertMenu( MAC_WXHMENU(menu->GetHMenu()) , m_menus[pos+1]->MacGetMenuId() ) ;
e7549107
SC
864 }
865
866#if wxUSE_ACCEL
867 if ( menu->HasAccels() )
e9576ca5 868 {
e7549107
SC
869 // need to rebuild accell table
870 RebuildAccelTable();
e9576ca5 871 }
e7549107 872#endif // wxUSE_ACCEL
e9576ca5 873
e7549107 874 Refresh();
e9576ca5 875 }
e7549107
SC
876
877 return TRUE;
e9576ca5
SC
878}
879
519cb848
SC
880void wxMenuBar::MacMenuSelect(wxEvtHandler* handler, long when , int macMenuId, int macMenuItemNum)
881{
8caf72d3
GD
882 // first scan fast for direct commands, i.e. menus which have these commands directly in their own list
883
884 if ( macMenuId == kwxMacAppleMenuId && macMenuItemNum == 1 )
885 {
886 wxCommandEvent event(wxEVT_COMMAND_MENU_SELECTED, wxApp::s_macAboutMenuItemId );
887 event.m_timeStamp = when;
888 event.SetEventObject(handler);
889 event.SetInt( wxApp::s_macAboutMenuItemId );
890 handler->ProcessEvent(event);
891 }
892 else
893 {
2b8a6962 894 for (size_t i = 0; i < m_menus.GetCount() ; i++)
8caf72d3
GD
895 {
896 if ( m_menus[i]->MacGetMenuId() == macMenuId || ( macMenuId == kHMHelpMenuID && ( m_titles[i] == "?" || m_titles[i] == "&?" || m_titles[i] == wxApp::s_macHelpMenuTitleName ) ) )
897 {
898 if ( m_menus[i]->MacMenuSelect( handler , when , macMenuId , macMenuItemNum ) )
899 return ;
900 else
901 {
902 //TODO flag this as an error since it must contain the item
903 return ;
904 }
905 }
906 }
519cb848 907
2b8a6962 908 for (size_t i = 0; i < m_menus.GetCount(); i++)
519cb848
SC
909 {
910 if ( m_menus[i]->MacMenuSelect( handler , when , macMenuId , macMenuItemNum ) )
911 {
912 break ;
913 }
51abe921 914 }
519cb848
SC
915 }
916}
e9576ca5 917
51abe921
SC
918wxMenu *wxMenuBar::Remove(size_t pos)
919{
920 wxMenu *menu = wxMenuBarBase::Remove(pos);
921 if ( !menu )
922 return NULL;
923
924 if ( IsAttached() )
925 {
926 if (s_macInstalledMenuBar == this)
927 {
928 ::DeleteMenu( menu->MacGetMenuId() /* m_menus[pos]->MacGetMenuId() */ ) ;
929 }
930
931 menu->Detach();
932
933#if wxUSE_ACCEL
934 if ( menu->HasAccels() )
935 {
936 // need to rebuild accell table
937 RebuildAccelTable();
938 }
939#endif // wxUSE_ACCEL
940
941 Refresh();
942 }
943
944 m_titles.Remove(pos);
945
946 return menu;
947}
948
949bool wxMenuBar::Append(wxMenu *menu, const wxString& title)
950{
951 WXHMENU submenu = menu ? menu->GetHMenu() : 0;
952 wxCHECK_MSG( submenu, FALSE, wxT("can't append invalid menu to menubar") );
953
954 if ( !wxMenuBarBase::Append(menu, title) )
955 return FALSE;
956
51abe921 957 m_titles.Add(title);
40325b26
SC
958
959 Str255 label ;
960 wxMenuItem::MacBuildMenuString( label, NULL , NULL , title , false );
961 UMASetMenuTitle( MAC_WXHMENU(menu->GetHMenu()) , label ) ;
51abe921
SC
962
963 if ( IsAttached() )
964 {
40325b26
SC
965 if (s_macInstalledMenuBar == this)
966 {
967 ::InsertMenu( MAC_WXHMENU(menu->GetHMenu()) , 0 ) ;
968 }
51abe921
SC
969
970#if wxUSE_ACCEL
971 if ( menu->HasAccels() )
972 {
973 // need to rebuild accell table
974 RebuildAccelTable();
975 }
976#endif // wxUSE_ACCEL
977
978 Refresh();
979 }
980
981 return TRUE;
982}
983
90b959ae 984void wxMenuBar::Detach()
2f1ae414 985{
90b959ae
SC
986 wxMenuBarBase::Detach() ;
987}
2f1ae414 988
90b959ae
SC
989void wxMenuBar::Attach(wxFrame *frame)
990{
991 wxMenuBarBase::Attach( frame ) ;
2f1ae414
SC
992
993#if wxUSE_ACCEL
994 RebuildAccelTable();
995#endif // wxUSE_ACCEL
996}
51abe921
SC
997// ---------------------------------------------------------------------------
998// wxMenuBar searching for menu items
999// ---------------------------------------------------------------------------
1000
1001// Find the itemString in menuString, and return the item id or wxNOT_FOUND
1002int wxMenuBar::FindMenuItem(const wxString& menuString,
1003 const wxString& itemString) const
1004{
1005 wxString menuLabel = wxStripMenuCodes(menuString);
1006 size_t count = GetMenuCount();
1007 for ( size_t i = 0; i < count; i++ )
1008 {
1009 wxString title = wxStripMenuCodes(m_titles[i]);
1010 if ( menuString == title )
1011 return m_menus[i]->FindItem(itemString);
1012 }
1013
1014 return wxNOT_FOUND;
1015}
1016
1017wxMenuItem *wxMenuBar::FindItem(int id, wxMenu **itemMenu) const
1018{
1019 if ( itemMenu )
1020 *itemMenu = NULL;
1021
1022 wxMenuItem *item = NULL;
1023 size_t count = GetMenuCount();
1024 for ( size_t i = 0; !item && (i < count); i++ )
1025 {
1026 item = m_menus[i]->FindItem(id, itemMenu);
1027 }
1028
1029 return item;
1030}
1031
1032