]> git.saurik.com Git - wxWidgets.git/blame - src/mac/menu.cpp
Under Cygwin, in platform.h default to wxMSW unless otherwise specified.
[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
eb22f2a6
GD
13#ifdef __GNUG__
14#pragma implementation "menu.h"
15#pragma implementation "menuitem.h"
16#endif
17
e9576ca5
SC
18// ============================================================================
19// headers & declarations
20// ============================================================================
21
22// wxWindows headers
23// -----------------
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"
2b5f62a0 31#include "wx/frame.h"
e9576ca5 32
519cb848
SC
33#include "wx/mac/uma.h"
34
e9576ca5
SC
35// other standard headers
36// ----------------------
37#include <string.h>
38
2f1ae414 39#if !USE_SHARED_LIBRARY
e9576ca5
SC
40IMPLEMENT_DYNAMIC_CLASS(wxMenu, wxEvtHandler)
41IMPLEMENT_DYNAMIC_CLASS(wxMenuBar, wxEvtHandler)
2f1ae414 42#endif
e9576ca5 43
519cb848
SC
44// the (popup) menu title has this special id
45static const int idMenuTitle = -2;
b03e4fcd 46static MenuItemIndex firstUserHelpMenuItem = 0 ;
519cb848
SC
47
48const short kwxMacMenuBarResource = 1 ;
49const short kwxMacAppleMenuId = 1 ;
50
e9576ca5
SC
51// ============================================================================
52// implementation
53// ============================================================================
54
519cb848 55
e9576ca5
SC
56// Menus
57
58// Construct a menu with optional title (then use append)
519cb848 59
f5c6eb5c 60#ifdef __DARWIN__
82ca6dbc
GD
61short wxMenu::s_macNextMenuId = 3 ;
62#else
519cb848 63short wxMenu::s_macNextMenuId = 2 ;
82ca6dbc 64#endif
519cb848 65
e7549107 66void wxMenu::Init()
e9576ca5 67{
e7549107
SC
68 m_doBreak = FALSE;
69
70 // create the menu
71 Str255 label;
2f1ae414 72 wxMenuItem::MacBuildMenuString( label, NULL , NULL , m_title , false );
e7549107 73 m_macMenuId = s_macNextMenuId++;
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);
2b5f62a0 213 SetMenuItemCommandID( MAC_WXHMENU(m_hMenu) , CountMenuItems(MAC_WXHMENU(m_hMenu)) , pItem->GetId() ) ;
93e5d899
SC
214 if ( pItem->GetBitmap().Ok() )
215 {
216 ControlButtonContentInfo info ;
2b5f62a0 217 wxMacCreateBitmapButton( &info , pItem->GetBitmap() , kControlContentCIconHandle ) ;
93e5d899
SC
218 if ( info.contentType != kControlNoContent )
219 {
220 if ( info.contentType == kControlContentCIconHandle )
221 SetMenuItemIconHandle( MAC_WXHMENU(m_hMenu) , CountMenuItems(MAC_WXHMENU(m_hMenu) ) ,
222 kMenuColorIconType , (Handle) info.u.cIconHandle ) ;
223 }
224
225 }
e7549107
SC
226 }
227 else
228 {
76a5e5d2 229 UMAInsertMenuItem(MAC_WXHMENU(m_hMenu), label , pos,key,modifiers);
2b5f62a0 230 SetMenuItemCommandID( MAC_WXHMENU(m_hMenu) , pos , pItem->GetId() ) ;
93e5d899
SC
231 if ( pItem->GetBitmap().Ok() )
232 {
233 ControlButtonContentInfo info ;
2b5f62a0 234 wxMacCreateBitmapButton( &info , pItem->GetBitmap() , kControlContentCIconHandle ) ;
93e5d899
SC
235 if ( info.contentType != kControlNoContent )
236 {
237 if ( info.contentType == kControlContentCIconHandle )
238 SetMenuItemIconHandle( MAC_WXHMENU(m_hMenu) , pos ,
239 kMenuColorIconType , (Handle) info.u.cIconHandle ) ;
240 }
241
242 }
e7549107 243 }
519cb848
SC
244 if ( pItem->GetId() == idMenuTitle )
245 {
e7549107
SC
246 if ( pos == (size_t)-1 )
247 {
76a5e5d2 248 UMADisableMenuItem(MAC_WXHMENU(m_hMenu) , CountMenuItems(MAC_WXHMENU(m_hMenu) ) ) ;
e7549107
SC
249 }
250 else
251 {
76a5e5d2 252 UMADisableMenuItem(MAC_WXHMENU(m_hMenu) , pos + 1 ) ;
e7549107 253 }
519cb848
SC
254 }
255 }
256 }
e7549107
SC
257 // if we're already attached to the menubar, we must update it
258 if ( IsAttached() )
259 {
260 m_menuBar->Refresh();
261 }
262 return TRUE ;
e9576ca5
SC
263}
264
e7549107 265bool wxMenu::DoAppend(wxMenuItem *item)
e9576ca5 266{
e7549107 267 return wxMenuBase::DoAppend(item) && DoInsertOrAppend(item);
e9576ca5
SC
268}
269
e7549107 270bool wxMenu::DoInsert(size_t pos, wxMenuItem *item)
e9576ca5 271{
e7549107 272 return wxMenuBase::DoInsert(pos, item) && DoInsertOrAppend(item, pos);
e9576ca5
SC
273}
274
e7549107 275wxMenuItem *wxMenu::DoRemove(wxMenuItem *item)
e9576ca5 276{
e7549107
SC
277 // we need to find the items position in the child list
278 size_t pos;
279 wxMenuItemList::Node *node = GetMenuItems().GetFirst();
280 for ( pos = 0; node; pos++ )
281 {
282 if ( node->GetData() == item )
283 break;
e9576ca5 284
e7549107 285 node = node->GetNext();
e9576ca5
SC
286 }
287
e7549107
SC
288 // DoRemove() (unlike Remove) can only be called for existing item!
289 wxCHECK_MSG( node, NULL, wxT("bug in wxMenu::Remove logic") );
519cb848 290
e7549107
SC
291#if wxUSE_ACCEL
292 // remove the corresponding accel from the accel table
293 int n = FindAccel(item->GetId());
294 if ( n != wxNOT_FOUND )
295 {
296 delete m_accels[n];
519cb848 297
3ef585df 298 m_accels.RemoveAt(n);
e7549107
SC
299 }
300 //else: this item doesn't have an accel, nothing to do
301#endif // wxUSE_ACCEL
e9576ca5 302
76a5e5d2 303 ::DeleteMenuItem(MAC_WXHMENU(m_hMenu) , pos + 1);
e9576ca5 304
e7549107
SC
305 if ( IsAttached() )
306 {
307 // otherwise, the chane won't be visible
308 m_menuBar->Refresh();
309 }
e9576ca5 310
e7549107
SC
311 // and from internal data structures
312 return wxMenuBase::DoRemove(item);
e9576ca5
SC
313}
314
e7549107
SC
315// ---------------------------------------------------------------------------
316// accelerator helpers
317// ---------------------------------------------------------------------------
e9576ca5 318
e7549107 319#if wxUSE_ACCEL
e9576ca5 320
e7549107
SC
321// create the wxAcceleratorEntries for our accels and put them into provided
322// array - return the number of accels we have
323size_t wxMenu::CopyAccels(wxAcceleratorEntry *accels) const
e9576ca5 324{
e7549107
SC
325 size_t count = GetAccelCount();
326 for ( size_t n = 0; n < count; n++ )
327 {
328 *accels++ = *m_accels[n];
329 }
e9576ca5 330
e7549107 331 return count;
e9576ca5
SC
332}
333
e7549107 334#endif // wxUSE_ACCEL
e9576ca5
SC
335
336void wxMenu::SetTitle(const wxString& label)
337{
519cb848 338 Str255 title ;
e9576ca5 339 m_title = label ;
2f1ae414 340 wxMenuItem::MacBuildMenuString( title, NULL , NULL , label , false );
76a5e5d2 341 UMASetMenuTitle(MAC_WXHMENU(m_hMenu) , title ) ;
e9576ca5 342}
e7549107 343bool wxMenu::ProcessCommand(wxCommandEvent & event)
e9576ca5
SC
344{
345 bool processed = FALSE;
346
e7549107 347#if WXWIN_COMPATIBILITY
e9576ca5
SC
348 // Try a callback
349 if (m_callback)
350 {
e7549107
SC
351 (void)(*(m_callback))(*this, event);
352 processed = TRUE;
e9576ca5 353 }
e7549107 354#endif WXWIN_COMPATIBILITY
e9576ca5
SC
355
356 // Try the menu's event handler
357 if ( !processed && GetEventHandler())
358 {
e7549107 359 processed = GetEventHandler()->ProcessEvent(event);
e9576ca5 360 }
519cb848 361
e7549107
SC
362 // Try the window the menu was popped up from (and up through the
363 // hierarchy)
364 wxWindow *win = GetInvokingWindow();
365 if ( !processed && win )
366 processed = win->GetEventHandler()->ProcessEvent(event);
367
368 return processed;
369}
370
371
372// ---------------------------------------------------------------------------
373// other
374// ---------------------------------------------------------------------------
375
e7549107
SC
376wxWindow *wxMenu::GetWindow() const
377{
378 if ( m_invokingWindow != NULL )
379 return m_invokingWindow;
380 else if ( m_menuBar != NULL)
03e11df5 381 return (wxWindow *) m_menuBar->GetFrame();
e7549107
SC
382
383 return NULL;
384}
519cb848 385
519cb848
SC
386// helper functions returning the mac menu position for a certain item, note that this is
387// mac-wise 1 - based, i.e. the first item has index 1 whereas on MSWin it has pos 0
388
389int wxMenu::MacGetIndexFromId( int id )
390{
e7549107
SC
391 size_t pos;
392 wxMenuItemList::Node *node = GetMenuItems().GetFirst();
393 for ( pos = 0; node; pos++ )
519cb848 394 {
e7549107
SC
395 if ( node->GetData()->GetId() == id )
396 break;
519cb848 397
e7549107
SC
398 node = node->GetNext();
399 }
400
519cb848
SC
401 if (!node)
402 return 0;
403
404 return pos + 1 ;
405}
406
407int wxMenu::MacGetIndexFromItem( wxMenuItem *pItem )
408{
e7549107
SC
409 size_t pos;
410 wxMenuItemList::Node *node = GetMenuItems().GetFirst();
411 for ( pos = 0; node; pos++ )
519cb848 412 {
e7549107
SC
413 if ( node->GetData() == pItem )
414 break;
415
416 node = node->GetNext();
519cb848
SC
417 }
418
419 if (!node)
420 return 0;
421
422 return pos + 1 ;
423}
424
425void wxMenu::MacEnableMenu( bool bDoEnable )
426{
519cb848 427 if ( bDoEnable )
76a5e5d2 428 UMAEnableMenuItem(MAC_WXHMENU(m_hMenu) , 0 ) ;
519cb848 429 else
76a5e5d2 430 UMADisableMenuItem(MAC_WXHMENU(m_hMenu) , 0 ) ;
519cb848
SC
431
432 ::DrawMenuBar() ;
433}
434
e9576ca5 435// Menu Bar
519cb848
SC
436
437/*
438
439Mac Implementation note :
440
441The Mac has only one global menubar, so we attempt to install the currently
442active menubar from a frame, we currently don't take into account mdi-frames
443which would ask for menu-merging
444
445Secondly there is no mac api for changing a menubar that is not the current
446menubar, so we have to wait for preparing the actual menubar until the
447wxMenubar is to be used
448
449We can in subsequent versions use MacInstallMenuBar to provide some sort of
450auto-merge for MDI in case this will be necessary
451
452*/
453
454wxMenuBar* wxMenuBar::s_macInstalledMenuBar = NULL ;
455
e7549107 456void wxMenuBar::Init()
e9576ca5
SC
457{
458 m_eventHandler = this;
e9576ca5 459 m_menuBarFrame = NULL;
e9576ca5
SC
460}
461
51abe921
SC
462wxMenuBar::wxMenuBar()
463{
464 Init();
465}
466
467wxMenuBar::wxMenuBar( long WXUNUSED(style) )
468{
469 Init();
470}
471
e7549107
SC
472
473wxMenuBar::wxMenuBar(int count, wxMenu *menus[], const wxString titles[])
e9576ca5 474{
e7549107
SC
475 Init();
476
477 m_titles.Alloc(count);
478
479 for ( int i = 0; i < count; i++ )
480 {
481 m_menus.Append(menus[i]);
482 m_titles.Add(titles[i]);
483
484 menus[i]->Attach(this);
485 }
e9576ca5
SC
486}
487
488wxMenuBar::~wxMenuBar()
489{
519cb848
SC
490 if (s_macInstalledMenuBar == this)
491 {
492 ::ClearMenuBar();
493 s_macInstalledMenuBar = NULL;
494 }
495
e7549107
SC
496}
497
6d6da89c 498void wxMenuBar::Refresh(bool WXUNUSED(eraseBackground), const wxRect *WXUNUSED(rect))
e7549107
SC
499{
500 wxCHECK_RET( IsAttached(), wxT("can't refresh unatteched menubar") );
e9576ca5 501
e7549107 502 DrawMenuBar();
e9576ca5
SC
503}
504
51abe921
SC
505#if wxUSE_ACCEL
506
507void wxMenuBar::RebuildAccelTable()
508{
509 // merge the accelerators of all menus into one accel table
510 size_t nAccelCount = 0;
511 size_t i, count = GetMenuCount();
512 for ( i = 0; i < count; i++ )
513 {
514 nAccelCount += m_menus[i]->GetAccelCount();
515 }
516
517 if ( nAccelCount )
518 {
519 wxAcceleratorEntry *accelEntries = new wxAcceleratorEntry[nAccelCount];
520
521 nAccelCount = 0;
522 for ( i = 0; i < count; i++ )
523 {
524 nAccelCount += m_menus[i]->CopyAccels(&accelEntries[nAccelCount]);
525 }
526
527 m_accelTable = wxAcceleratorTable(nAccelCount, accelEntries);
528
529 delete [] accelEntries;
530 }
531}
532
533#endif // wxUSE_ACCEL
2b8a6962 534
519cb848
SC
535void wxMenuBar::MacInstallMenuBar()
536{
2b8a6962
GD
537 if ( s_macInstalledMenuBar == this )
538 return ;
41f38f4d 539
d9e054bc
SC
540 wxStAppResource resload ;
541
2b8a6962
GD
542 Handle menubar = ::GetNewMBar( kwxMacMenuBarResource ) ;
543 wxString message ;
544 wxCHECK_RET( menubar != NULL, "can't read MBAR resource" );
545 ::SetMenuBar( menubar ) ;
a3590de1
SC
546#if TARGET_API_MAC_CARBON
547 ::DisposeMenuBar( menubar ) ;
548#else
2b8a6962 549 ::DisposeHandle( menubar ) ;
a3590de1 550#endif
519cb848 551
a3590de1 552#if TARGET_API_MAC_OS8
2b8a6962 553 MenuHandle menu = ::GetMenuHandle( kwxMacAppleMenuId ) ;
d9e054bc
SC
554 if ( CountMenuItems( menu ) == 2 )
555 {
2b8a6962
GD
556 ::AppendResMenu(menu, 'DRVR');
557 }
a3590de1 558#endif
519cb848 559
2b8a6962 560 for (size_t i = 0; i < m_menus.GetCount(); i++)
519cb848 561 {
2b5f62a0 562 Str255 label;
eb22f2a6 563 wxwxMenuItemListNode *node;
2b5f62a0
VZ
564 wxMenuItem *item;
565 int pos ;
566 wxMenu* menu = m_menus[i] , *subMenu = NULL ;
567
568 if( m_titles[i] == "?" || m_titles[i] == "&?" || m_titles[i] == wxApp::s_macHelpMenuTitleName )
569 {
570 MenuHandle mh = NULL ;
571 if ( UMAGetHelpMenu( &mh , &firstUserHelpMenuItem) != noErr )
519cb848 572 {
b03e4fcd 573 continue ;
2b5f62a0 574 }
a3590de1
SC
575
576 for ( int i = CountMenuItems( mh ) ; i >= firstUserHelpMenuItem ; --i )
577 {
2b5f62a0 578 DeleteMenuItem( mh , i ) ;
a3590de1 579 }
2b5f62a0 580
eb22f2a6 581 for (pos = 0 , node = menu->GetMenuItems().GetFirst(); node; node = node->GetNext(), pos++)
2b5f62a0 582 {
eb22f2a6 583 item = (wxMenuItem *)node->GetData();
2b5f62a0
VZ
584 subMenu = item->GetSubMenu() ;
585 if (subMenu)
586 {
587 // we don't support hierarchical menus in the help menu yet
588 }
589 else
590 {
591 if ( item->IsSeparator() )
519cb848 592 {
2b5f62a0
VZ
593 if ( mh )
594 MacAppendMenu(mh, "\p-" );
519cb848 595 }
2b5f62a0 596 else
519cb848 597 {
2b5f62a0
VZ
598 Str255 label ;
599 UInt8 modifiers ;
600 SInt16 key ;
601 wxMenuItem::MacBuildMenuString( label, &key , &modifiers , item->GetText(), item->GetId() != wxApp::s_macAboutMenuItemId); // no shortcut in about menu
602 if ( label[0] == 0 )
519cb848 603 {
2b5f62a0
VZ
604 // we cannot add empty menus on mac
605 label[0] = 1 ;
606 label[1] = ' ' ;
519cb848 607 }
2b5f62a0
VZ
608 if ( item->GetId() == wxApp::s_macAboutMenuItemId )
609 {
610 ::SetMenuItemText( GetMenuHandle( kwxMacAppleMenuId ) , 1 , label );
611 UMAEnableMenuItem( GetMenuHandle( kwxMacAppleMenuId ) , 1 );
612 SetMenuItemCommandID( GetMenuHandle( kwxMacAppleMenuId ) , 1 , item->GetId() ) ;
613 }
519cb848
SC
614 else
615 {
2b5f62a0 616 if ( mh )
8208e181 617 {
2b5f62a0
VZ
618 UMAAppendMenuItem(mh, label , key , modifiers );
619 SetMenuItemCommandID( mh , CountMenuItems(mh) , item->GetId() ) ;
8208e181 620 }
519cb848
SC
621 }
622 }
623 }
624 }
2b5f62a0
VZ
625 }
626 else
627 {
628 wxMenuItem::MacBuildMenuString( label, NULL , NULL , m_titles[i] , false );
629 UMASetMenuTitle( MAC_WXHMENU(menu->GetHMenu()) , label ) ;
630 wxArrayPtrVoid submenus ;
631
eb22f2a6 632 for (pos = 0, node = menu->GetMenuItems().GetFirst(); node; node = node->GetNext(), pos++)
2b5f62a0 633 {
eb22f2a6 634 item = (wxMenuItem *)node->GetData();
2b5f62a0
VZ
635 subMenu = item->GetSubMenu() ;
636 if (subMenu)
9673f535 637 {
2b5f62a0
VZ
638 submenus.Add(subMenu) ;
639 }
640 }
641 ::InsertMenu(MAC_WXHMENU(m_menus[i]->GetHMenu()), 0);
642 for ( size_t i = 0 ; i < submenus.GetCount() ; ++i )
643 {
644 wxMenu* submenu = (wxMenu*) submenus[i] ;
eb22f2a6 645 wxwxMenuItemListNode *subnode;
2b5f62a0
VZ
646 wxMenuItem *subitem;
647 int subpos ;
eb22f2a6 648 for ( subpos = 0 , subnode = submenu->GetMenuItems().GetFirst(); subnode; subnode = subnode->GetNext(), subpos++)
9673f535 649 {
eb22f2a6 650 subitem = (wxMenuItem *)subnode->GetData();
9673f535
SC
651 wxMenu* itsSubMenu = subitem->GetSubMenu() ;
652 if (itsSubMenu)
653 {
654 submenus.Add(itsSubMenu) ;
655 }
656 }
2b5f62a0
VZ
657 ::InsertMenu( MAC_WXHMENU(submenu->GetHMenu()) , -1 ) ;
658 }
519cb848 659 }
2b5f62a0
VZ
660 }
661 ::DrawMenuBar() ;
519cb848
SC
662 s_macInstalledMenuBar = this;
663}
664
e7549107 665void wxMenuBar::EnableTop(size_t pos, bool enable)
e9576ca5 666{
e7549107
SC
667 wxCHECK_RET( IsAttached(), wxT("doesn't work with unattached menubars") );
668 m_menus[pos]->MacEnableMenu( enable ) ;
669 Refresh();
e9576ca5
SC
670}
671
e7549107 672void wxMenuBar::SetLabelTop(size_t pos, const wxString& label)
e9576ca5 673{
e7549107 674 wxCHECK_RET( pos < GetMenuCount(), wxT("invalid menu index") );
e9576ca5 675
e7549107 676 m_titles[pos] = label;
e9576ca5 677
e7549107
SC
678 if ( !IsAttached() )
679 {
e9576ca5 680 return;
e7549107 681 }
e9576ca5 682
519cb848 683 m_menus[pos]->SetTitle( label ) ;
e7549107 684 if (wxMenuBar::s_macInstalledMenuBar == this) // are we currently installed ?
519cb848 685 {
e7549107 686 ::SetMenuBar( GetMenuBar() ) ;
519cb848 687 ::InvalMenuBar() ;
519cb848 688 }
e9576ca5
SC
689}
690
e7549107 691wxString wxMenuBar::GetLabelTop(size_t pos) const
e9576ca5 692{
e7549107
SC
693 wxCHECK_MSG( pos < GetMenuCount(), wxEmptyString,
694 wxT("invalid menu index in wxMenuBar::GetLabelTop") );
519cb848 695
e7549107 696 return m_titles[pos];
e9576ca5
SC
697}
698
e7549107 699int wxMenuBar::FindMenu(const wxString& title)
e9576ca5 700{
e7549107 701 wxString menuTitle = wxStripMenuCodes(title);
e9576ca5 702
e7549107
SC
703 size_t count = GetMenuCount();
704 for ( size_t i = 0; i < count; i++ )
e9576ca5 705 {
e7549107
SC
706 wxString title = wxStripMenuCodes(m_titles[i]);
707 if ( menuTitle == title )
708 return i;
e9576ca5 709 }
e9576ca5 710
e7549107 711 return wxNOT_FOUND;
e9576ca5 712
e9576ca5
SC
713}
714
e7549107
SC
715
716// ---------------------------------------------------------------------------
717// wxMenuBar construction
718// ---------------------------------------------------------------------------
719
720// ---------------------------------------------------------------------------
721// wxMenuBar construction
722// ---------------------------------------------------------------------------
723
724wxMenu *wxMenuBar::Replace(size_t pos, wxMenu *menu, const wxString& title)
e9576ca5 725{
e7549107
SC
726 wxMenu *menuOld = wxMenuBarBase::Replace(pos, menu, title);
727 if ( !menuOld )
728 return FALSE;
729 m_titles[pos] = title;
e9576ca5 730
e7549107 731 if ( IsAttached() )
e9576ca5 732 {
e7549107
SC
733 if (s_macInstalledMenuBar == this)
734 {
72055702 735 ::DeleteMenu( menuOld->MacGetMenuId() /* m_menus[pos]->MacGetMenuId() */ ) ;
e7549107
SC
736 {
737 Str255 label;
2f1ae414 738 wxMenuItem::MacBuildMenuString( label, NULL , NULL , title , false );
76a5e5d2 739 UMASetMenuTitle( MAC_WXHMENU(menu->GetHMenu()) , label ) ;
e7549107
SC
740 if ( pos == m_menus.GetCount() - 1)
741 {
76a5e5d2 742 ::InsertMenu( MAC_WXHMENU(menu->GetHMenu()) , 0 ) ;
e7549107
SC
743 }
744 else
745 {
76a5e5d2 746 ::InsertMenu( MAC_WXHMENU(menu->GetHMenu()) , m_menus[pos+1]->MacGetMenuId() ) ;
e7549107
SC
747 }
748 }
749 }
e9576ca5 750
e9576ca5 751
e7549107
SC
752#if wxUSE_ACCEL
753 if ( menuOld->HasAccels() || menu->HasAccels() )
754 {
755 // need to rebuild accell table
756 RebuildAccelTable();
757 }
758#endif // wxUSE_ACCEL
e9576ca5 759
e7549107 760 Refresh();
e9576ca5 761 }
e9576ca5 762
e7549107 763 return menuOld;
e9576ca5
SC
764}
765
e7549107 766bool wxMenuBar::Insert(size_t pos, wxMenu *menu, const wxString& title)
e9576ca5 767{
e7549107
SC
768 if ( !wxMenuBarBase::Insert(pos, menu, title) )
769 return FALSE;
e9576ca5 770
e7549107 771 m_titles.Insert(title, pos);
e9576ca5 772
40325b26
SC
773 Str255 label ;
774 wxMenuItem::MacBuildMenuString( label, NULL , NULL , title , false );
775 UMASetMenuTitle( MAC_WXHMENU(menu->GetHMenu()) , label ) ;
e7549107
SC
776
777 if ( IsAttached() )
e9576ca5 778 {
40325b26 779 if ( pos == (size_t) -1 || pos + 1 == m_menus.GetCount() )
e7549107 780 {
76a5e5d2 781 ::InsertMenu( MAC_WXHMENU(menu->GetHMenu()) , 0 ) ;
e7549107
SC
782 }
783 else
784 {
76a5e5d2 785 ::InsertMenu( MAC_WXHMENU(menu->GetHMenu()) , m_menus[pos+1]->MacGetMenuId() ) ;
e7549107
SC
786 }
787
788#if wxUSE_ACCEL
789 if ( menu->HasAccels() )
e9576ca5 790 {
e7549107
SC
791 // need to rebuild accell table
792 RebuildAccelTable();
e9576ca5 793 }
e7549107 794#endif // wxUSE_ACCEL
e9576ca5 795
e7549107 796 Refresh();
e9576ca5 797 }
e7549107
SC
798
799 return TRUE;
e9576ca5
SC
800}
801
51abe921
SC
802wxMenu *wxMenuBar::Remove(size_t pos)
803{
804 wxMenu *menu = wxMenuBarBase::Remove(pos);
805 if ( !menu )
806 return NULL;
807
808 if ( IsAttached() )
809 {
810 if (s_macInstalledMenuBar == this)
811 {
812 ::DeleteMenu( menu->MacGetMenuId() /* m_menus[pos]->MacGetMenuId() */ ) ;
813 }
814
815 menu->Detach();
816
817#if wxUSE_ACCEL
818 if ( menu->HasAccels() )
819 {
820 // need to rebuild accell table
821 RebuildAccelTable();
822 }
823#endif // wxUSE_ACCEL
824
825 Refresh();
826 }
827
828 m_titles.Remove(pos);
829
830 return menu;
831}
832
833bool wxMenuBar::Append(wxMenu *menu, const wxString& title)
834{
835 WXHMENU submenu = menu ? menu->GetHMenu() : 0;
836 wxCHECK_MSG( submenu, FALSE, wxT("can't append invalid menu to menubar") );
837
838 if ( !wxMenuBarBase::Append(menu, title) )
839 return FALSE;
840
51abe921 841 m_titles.Add(title);
40325b26
SC
842
843 Str255 label ;
844 wxMenuItem::MacBuildMenuString( label, NULL , NULL , title , false );
845 UMASetMenuTitle( MAC_WXHMENU(menu->GetHMenu()) , label ) ;
51abe921
SC
846
847 if ( IsAttached() )
848 {
40325b26
SC
849 if (s_macInstalledMenuBar == this)
850 {
851 ::InsertMenu( MAC_WXHMENU(menu->GetHMenu()) , 0 ) ;
852 }
51abe921
SC
853
854#if wxUSE_ACCEL
855 if ( menu->HasAccels() )
856 {
857 // need to rebuild accell table
858 RebuildAccelTable();
859 }
860#endif // wxUSE_ACCEL
861
862 Refresh();
863 }
864
865 return TRUE;
866}
867
2b5f62a0
VZ
868static void wxMenubarUnsetInvokingWindow( wxMenu *menu )
869{
870 menu->SetInvokingWindow( (wxWindow*) NULL );
871
872 wxMenuItemList::Node *node = menu->GetMenuItems().GetFirst();
873 while (node)
874 {
875 wxMenuItem *menuitem = node->GetData();
876 if (menuitem->IsSubMenu())
877 wxMenubarUnsetInvokingWindow( menuitem->GetSubMenu() );
878 node = node->GetNext();
879 }
880}
881
882static void wxMenubarSetInvokingWindow( wxMenu *menu, wxWindow *win )
883{
884 menu->SetInvokingWindow( win );
885
886 wxMenuItemList::Node *node = menu->GetMenuItems().GetFirst();
887 while (node)
888 {
889 wxMenuItem *menuitem = node->GetData();
890 if (menuitem->IsSubMenu())
891 wxMenubarSetInvokingWindow( menuitem->GetSubMenu() , win );
892 node = node->GetNext();
893 }
894}
895
896void wxMenuBar::UnsetInvokingWindow()
897{
898 wxMenuList::Node *node = m_menus.GetFirst();
899 while (node)
900 {
901 wxMenu *menu = node->GetData();
902 wxMenubarUnsetInvokingWindow( menu );
903 node = node->GetNext();
904 }
905}
906
907void wxMenuBar::SetInvokingWindow(wxFrame *frame)
908{
909 wxMenuList::Node *node = m_menus.GetFirst();
910 while (node)
911 {
912 wxMenu *menu = node->GetData();
913 wxMenubarSetInvokingWindow( menu, frame );
914 node = node->GetNext();
915 }
916}
917
90b959ae 918void wxMenuBar::Detach()
2f1ae414 919{
90b959ae
SC
920 wxMenuBarBase::Detach() ;
921}
2f1ae414 922
90b959ae
SC
923void wxMenuBar::Attach(wxFrame *frame)
924{
925 wxMenuBarBase::Attach( frame ) ;
2f1ae414
SC
926#if wxUSE_ACCEL
927 RebuildAccelTable();
928#endif // wxUSE_ACCEL
929}
51abe921
SC
930// ---------------------------------------------------------------------------
931// wxMenuBar searching for menu items
932// ---------------------------------------------------------------------------
933
934// Find the itemString in menuString, and return the item id or wxNOT_FOUND
935int wxMenuBar::FindMenuItem(const wxString& menuString,
936 const wxString& itemString) const
937{
938 wxString menuLabel = wxStripMenuCodes(menuString);
939 size_t count = GetMenuCount();
940 for ( size_t i = 0; i < count; i++ )
941 {
942 wxString title = wxStripMenuCodes(m_titles[i]);
943 if ( menuString == title )
944 return m_menus[i]->FindItem(itemString);
945 }
946
947 return wxNOT_FOUND;
948}
949
950wxMenuItem *wxMenuBar::FindItem(int id, wxMenu **itemMenu) const
951{
952 if ( itemMenu )
953 *itemMenu = NULL;
954
955 wxMenuItem *item = NULL;
956 size_t count = GetMenuCount();
957 for ( size_t i = 0; !item && (i < count); i++ )
958 {
959 item = m_menus[i]->FindItem(id, itemMenu);
960 }
961
962 return item;
963}
964
965