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