]> git.saurik.com Git - wxWidgets.git/blame - src/mac/menu.cpp
Added wxYieldIfNeeded
[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{
634 Handle menubar = ::GetNewMBar( kwxMacMenuBarResource ) ;
635 wxString message ;
636 wxCHECK_RET( menubar != NULL, "can't read MBAR resource" );
637 ::SetMenuBar( menubar ) ;
638 ::DisposeHandle( menubar ) ;
639
640 MenuHandle menu = ::GetMenuHandle( kwxMacAppleMenuId ) ;
641 ::AppendResMenu(menu, 'DRVR');
642
e7549107 643 for (int i = 0; i < m_menus.GetCount(); i++)
519cb848
SC
644 {
645 Str255 label;
646 wxNode *node;
647 wxMenuItem *item;
648 int pos ;
649 wxMenu* menu = m_menus[i] , *subMenu = NULL ;
650
2f1ae414
SC
651#if !TARGET_CARBON
652 /* the help menu does not exist in CARBON anymore */
8208e181 653 if( m_titles[i] == "?" || m_titles[i] == "&?" || m_titles[i] == wxApp::s_macHelpMenuTitleName )
519cb848
SC
654 {
655 MenuHandle mh = NULL ;
656 if ( HMGetHelpMenuHandle( &mh ) != noErr )
657 {
658 continue ;
659 }
660 if ( formerHelpMenuItems == 0 )
661 {
662 if( mh )
663 formerHelpMenuItems = CountMenuItems( mh ) ;
664 }
665
2f1ae414
SC
666 for (pos = 0 , node = menu->GetMenuItems().First(); node; node = node->Next(), pos++)
667 {
519cb848
SC
668 item = (wxMenuItem *)node->Data();
669 subMenu = item->GetSubMenu() ;
670 if (subMenu)
671 {
672 // we don't support hierarchical menus in the help menu yet
673 }
674 else
675 {
8208e181 676 if ( item->IsSeparator() )
519cb848 677 {
8208e181 678 if ( mh )
2f1ae414 679 UMAAppendMenuItem(mh, "\p-" );
519cb848 680 }
519cb848
SC
681 else
682 {
8208e181 683 Str255 label ;
2f1ae414
SC
684 UInt8 modifiers ;
685 SInt16 key ;
686 wxMenuItem::MacBuildMenuString( label, &key , &modifiers , item->GetText(), item->GetId() != wxApp::s_macAboutMenuItemId); // no shortcut in about menu
8208e181
SC
687 if ( label[0] == 0 )
688 {
689 // we cannot add empty menus on mac
690 label[0] = 1 ;
691 label[1] = ' ' ;
692 }
693 if ( item->GetId() == wxApp::s_macAboutMenuItemId )
694 {
2f1ae414
SC
695 UMASetMenuItemText( GetMenuHandle( kwxMacAppleMenuId ) , 1 , label );
696 UMAEnableMenuItem( GetMenuHandle( kwxMacAppleMenuId ) , 1 );
8208e181
SC
697 }
698 else
699 {
700 if ( mh )
2f1ae414 701 UMAAppendMenuItem(mh, label , key , modifiers );
8208e181 702 }
519cb848
SC
703 }
704 }
705 }
706 }
5b781a67
SC
707#else
708 if( m_titles[i] == "?" || m_titles[i] == "&?" || m_titles[i] == wxApp::s_macHelpMenuTitleName )
709 {
710 wxMenuItem::MacBuildMenuString( label, NULL , NULL , m_titles[i] , false );
711 UMASetMenuTitle( menu->GetHMenu() , label ) ;
712
713 for (pos = 0 , node = menu->GetMenuItems().First(); node; node = node->Next(), pos++)
714 {
715 item = (wxMenuItem *)node->Data();
716 subMenu = item->GetSubMenu() ;
717 if (subMenu)
718 {
719 UMAInsertMenu( subMenu->GetHMenu() , -1 ) ;
720 }
721 else
722 {
723 if ( item->GetId() == wxApp::s_macAboutMenuItemId )
724 {
725 Str255 label ;
726 UInt8 modifiers ;
727 SInt16 key ;
728 wxMenuItem::MacBuildMenuString( label, &key , &modifiers , item->GetText(), item->GetId() != wxApp::s_macAboutMenuItemId); // no shortcut in about menu
729 UMASetMenuItemText( GetMenuHandle( kwxMacAppleMenuId ) , 1 , label );
730 UMAEnableMenuItem( GetMenuHandle( kwxMacAppleMenuId ) , 1 );
731 }
732 }
733 }
734 UMAInsertMenu(m_menus[i]->GetHMenu(), 0);
735 }
2f1ae414 736#endif
5b781a67 737 else
519cb848 738 {
2f1ae414 739 wxMenuItem::MacBuildMenuString( label, NULL , NULL , m_titles[i] , false );
e7549107 740 UMASetMenuTitle( menu->GetHMenu() , label ) ;
2f1ae414
SC
741 for (pos = 0, node = menu->GetMenuItems().First(); node; node = node->Next(), pos++)
742 {
519cb848
SC
743 item = (wxMenuItem *)node->Data();
744 subMenu = item->GetSubMenu() ;
745 if (subMenu)
746 {
2f1ae414 747 UMAInsertMenu( subMenu->GetHMenu() , -1 ) ;
519cb848
SC
748 }
749 }
2f1ae414 750 UMAInsertMenu(m_menus[i]->GetHMenu(), 0);
519cb848
SC
751 }
752 }
2f1ae414 753 UMADrawMenuBar() ;
519cb848
SC
754
755 s_macInstalledMenuBar = this;
756}
757
e7549107 758void wxMenuBar::EnableTop(size_t pos, bool enable)
e9576ca5 759{
e7549107
SC
760 wxCHECK_RET( IsAttached(), wxT("doesn't work with unattached menubars") );
761 m_menus[pos]->MacEnableMenu( enable ) ;
762 Refresh();
e9576ca5
SC
763}
764
e7549107 765void wxMenuBar::SetLabelTop(size_t pos, const wxString& label)
e9576ca5 766{
e7549107 767 wxCHECK_RET( pos < GetMenuCount(), wxT("invalid menu index") );
e9576ca5 768
e7549107 769 m_titles[pos] = label;
e9576ca5 770
e7549107
SC
771 if ( !IsAttached() )
772 {
e9576ca5 773 return;
e7549107 774 }
e9576ca5 775
519cb848 776 m_menus[pos]->SetTitle( label ) ;
e7549107 777 if (wxMenuBar::s_macInstalledMenuBar == this) // are we currently installed ?
519cb848 778 {
e7549107 779 ::SetMenuBar( GetMenuBar() ) ;
519cb848 780 ::InvalMenuBar() ;
519cb848 781 }
e9576ca5
SC
782}
783
e7549107 784wxString wxMenuBar::GetLabelTop(size_t pos) const
e9576ca5 785{
e7549107
SC
786 wxCHECK_MSG( pos < GetMenuCount(), wxEmptyString,
787 wxT("invalid menu index in wxMenuBar::GetLabelTop") );
519cb848 788
e7549107 789 return m_titles[pos];
e9576ca5
SC
790}
791
e7549107 792int wxMenuBar::FindMenu(const wxString& title)
e9576ca5 793{
e7549107 794 wxString menuTitle = wxStripMenuCodes(title);
e9576ca5 795
e7549107
SC
796 size_t count = GetMenuCount();
797 for ( size_t i = 0; i < count; i++ )
e9576ca5 798 {
e7549107
SC
799 wxString title = wxStripMenuCodes(m_titles[i]);
800 if ( menuTitle == title )
801 return i;
e9576ca5 802 }
e9576ca5 803
e7549107 804 return wxNOT_FOUND;
e9576ca5 805
e9576ca5
SC
806}
807
e7549107
SC
808
809// ---------------------------------------------------------------------------
810// wxMenuBar construction
811// ---------------------------------------------------------------------------
812
813// ---------------------------------------------------------------------------
814// wxMenuBar construction
815// ---------------------------------------------------------------------------
816
817wxMenu *wxMenuBar::Replace(size_t pos, wxMenu *menu, const wxString& title)
e9576ca5 818{
e7549107
SC
819 wxMenu *menuOld = wxMenuBarBase::Replace(pos, menu, title);
820 if ( !menuOld )
821 return FALSE;
822 m_titles[pos] = title;
e9576ca5 823
e7549107 824 if ( IsAttached() )
e9576ca5 825 {
e7549107
SC
826 if (s_macInstalledMenuBar == this)
827 {
2f1ae414 828 UMADeleteMenu( menuOld->MacGetMenuId() /* m_menus[pos]->MacGetMenuId() */ ) ;
e7549107
SC
829 {
830 Str255 label;
2f1ae414 831 wxMenuItem::MacBuildMenuString( label, NULL , NULL , title , false );
e7549107
SC
832 UMASetMenuTitle( menu->GetHMenu() , label ) ;
833 if ( pos == m_menus.GetCount() - 1)
834 {
2f1ae414 835 UMAInsertMenu( menu->GetHMenu() , 0 ) ;
e7549107
SC
836 }
837 else
838 {
2f1ae414 839 UMAInsertMenu( menu->GetHMenu() , m_menus[pos+1]->MacGetMenuId() ) ;
e7549107
SC
840 }
841 }
842 }
e9576ca5 843
e9576ca5 844
e7549107
SC
845#if wxUSE_ACCEL
846 if ( menuOld->HasAccels() || menu->HasAccels() )
847 {
848 // need to rebuild accell table
849 RebuildAccelTable();
850 }
851#endif // wxUSE_ACCEL
e9576ca5 852
e7549107 853 Refresh();
e9576ca5 854 }
e9576ca5 855
e7549107 856 return menuOld;
e9576ca5
SC
857}
858
e7549107 859bool wxMenuBar::Insert(size_t pos, wxMenu *menu, const wxString& title)
e9576ca5 860{
e7549107
SC
861 if ( !wxMenuBarBase::Insert(pos, menu, title) )
862 return FALSE;
e9576ca5 863
e7549107 864 m_titles.Insert(title, pos);
e9576ca5 865
e7549107
SC
866 menu->Attach(this);
867
868 if ( IsAttached() )
e9576ca5 869 {
e7549107
SC
870 if ( pos == (size_t) -1 )
871 {
872 ::InsertMenu( menu->GetHMenu() , 0 ) ;
873 }
874 else
875 {
876 ::InsertMenu( menu->GetHMenu() , m_menus[pos+1]->MacGetMenuId() ) ;
877 }
878
879#if wxUSE_ACCEL
880 if ( menu->HasAccels() )
e9576ca5 881 {
e7549107
SC
882 // need to rebuild accell table
883 RebuildAccelTable();
e9576ca5 884 }
e7549107 885#endif // wxUSE_ACCEL
e9576ca5 886
e7549107 887 Refresh();
e9576ca5 888 }
e7549107
SC
889
890 return TRUE;
e9576ca5
SC
891}
892
519cb848
SC
893void wxMenuBar::MacMenuSelect(wxEvtHandler* handler, long when , int macMenuId, int macMenuItemNum)
894{
895 // first scan fast for direct commands, i.e. menus which have these commands directly in their own list
896
897 if ( macMenuId == kwxMacAppleMenuId && macMenuItemNum == 1 )
898 {
899 wxCommandEvent event(wxEVT_COMMAND_MENU_SELECTED, wxApp::s_macAboutMenuItemId );
900 event.m_timeStamp = when;
901 event.SetEventObject(handler);
902 event.SetInt( wxApp::s_macAboutMenuItemId );
903 handler->ProcessEvent(event);
904 }
905 else
906 {
e7549107 907 for (int i = 0; i < m_menus.GetCount() ; i++)
519cb848 908 {
03e11df5
GD
909 if ( m_menus[i]->MacGetMenuId() == macMenuId
910#ifndef __WXMAC_X__
911 ||
8208e181 912 ( macMenuId == kHMHelpMenuID && ( m_titles[i] == "?" || m_titles[i] == "&?" || m_titles[i] == wxApp::s_macHelpMenuTitleName ) )
03e11df5 913#endif
519cb848
SC
914 )
915 {
916 if ( m_menus[i]->MacMenuSelect( handler , when , macMenuId , macMenuItemNum ) )
917 return ;
918 else
919 {
920 //TODO flag this as an error since it must contain the item
921 return ;
922 }
923 }
924 }
925
e7549107 926 for (int i = 0; i < m_menus.GetCount(); i++)
519cb848
SC
927 {
928 if ( m_menus[i]->MacMenuSelect( handler , when , macMenuId , macMenuItemNum ) )
929 {
930 break ;
931 }
51abe921 932 }
519cb848
SC
933 }
934}
e9576ca5 935
51abe921
SC
936wxMenu *wxMenuBar::Remove(size_t pos)
937{
938 wxMenu *menu = wxMenuBarBase::Remove(pos);
939 if ( !menu )
940 return NULL;
941
942 if ( IsAttached() )
943 {
944 if (s_macInstalledMenuBar == this)
945 {
946 ::DeleteMenu( menu->MacGetMenuId() /* m_menus[pos]->MacGetMenuId() */ ) ;
947 }
948
949 menu->Detach();
950
951#if wxUSE_ACCEL
952 if ( menu->HasAccels() )
953 {
954 // need to rebuild accell table
955 RebuildAccelTable();
956 }
957#endif // wxUSE_ACCEL
958
959 Refresh();
960 }
961
962 m_titles.Remove(pos);
963
964 return menu;
965}
966
967bool wxMenuBar::Append(wxMenu *menu, const wxString& title)
968{
969 WXHMENU submenu = menu ? menu->GetHMenu() : 0;
970 wxCHECK_MSG( submenu, FALSE, wxT("can't append invalid menu to menubar") );
971
972 if ( !wxMenuBarBase::Append(menu, title) )
973 return FALSE;
974
975 menu->Attach(this);
976
977 m_titles.Add(title);
978
979 if ( IsAttached() )
980 {
981 if (s_macInstalledMenuBar == this)
982 {
983 ::InsertMenu( menu->GetHMenu() , 0 ) ;
984 }
985
986#if wxUSE_ACCEL
987 if ( menu->HasAccels() )
988 {
989 // need to rebuild accell table
990 RebuildAccelTable();
991 }
992#endif // wxUSE_ACCEL
993
994 Refresh();
995 }
996
997 return TRUE;
998}
999
2f1ae414
SC
1000void wxMenuBar::Attach(wxFrame *frame)
1001{
1002// wxASSERT_MSG( !IsAttached(), wxT("menubar already attached!") );
1003
1004 m_menuBarFrame = frame;
1005
1006#if wxUSE_ACCEL
1007 RebuildAccelTable();
1008#endif // wxUSE_ACCEL
1009}
51abe921
SC
1010// ---------------------------------------------------------------------------
1011// wxMenuBar searching for menu items
1012// ---------------------------------------------------------------------------
1013
1014// Find the itemString in menuString, and return the item id or wxNOT_FOUND
1015int wxMenuBar::FindMenuItem(const wxString& menuString,
1016 const wxString& itemString) const
1017{
1018 wxString menuLabel = wxStripMenuCodes(menuString);
1019 size_t count = GetMenuCount();
1020 for ( size_t i = 0; i < count; i++ )
1021 {
1022 wxString title = wxStripMenuCodes(m_titles[i]);
1023 if ( menuString == title )
1024 return m_menus[i]->FindItem(itemString);
1025 }
1026
1027 return wxNOT_FOUND;
1028}
1029
1030wxMenuItem *wxMenuBar::FindItem(int id, wxMenu **itemMenu) const
1031{
1032 if ( itemMenu )
1033 *itemMenu = NULL;
1034
1035 wxMenuItem *item = NULL;
1036 size_t count = GetMenuCount();
1037 for ( size_t i = 0; !item && (i < count); i++ )
1038 {
1039 item = m_menus[i]->FindItem(id, itemMenu);
1040 }
1041
1042 return item;
1043}
1044
1045