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