]> git.saurik.com Git - wxWidgets.git/blame - src/mac/carbon/menu.cpp
remove the selection when SetSelection(-1) is called instead of asserting (as documented)
[wxWidgets.git] / src / mac / carbon / menu.cpp
CommitLineData
e9576ca5
SC
1/////////////////////////////////////////////////////////////////////////////
2// Name: menu.cpp
3// Purpose: wxMenu, wxMenuBar, wxMenuItem
a31a5f85 4// Author: Stefan Csomor
e9576ca5 5// Modified by:
a31a5f85 6// Created: 1998-01-01
e9576ca5 7// RCS-ID: $Id$
a31a5f85 8// Copyright: (c) Stefan Csomor
65571936 9// Licence: wxWindows licence
e9576ca5
SC
10/////////////////////////////////////////////////////////////////////////////
11
eb22f2a6
GD
12#ifdef __GNUG__
13#pragma implementation "menu.h"
14#pragma implementation "menuitem.h"
15#endif
16
e9576ca5
SC
17// ============================================================================
18// headers & declarations
19// ============================================================================
20
77ffb593 21// wxWidgets headers
e9576ca5
SC
22// -----------------
23
03e11df5 24#include "wx/app.h"
e9576ca5
SC
25#include "wx/menu.h"
26#include "wx/menuitem.h"
03e11df5 27#include "wx/window.h"
e9576ca5
SC
28#include "wx/log.h"
29#include "wx/utils.h"
2b5f62a0 30#include "wx/frame.h"
e9576ca5 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 43// the (popup) menu title has this special id
de5914a1 44static const int idMenuTitle = -3;
b03e4fcd 45static MenuItemIndex firstUserHelpMenuItem = 0 ;
519cb848
SC
46
47const short kwxMacMenuBarResource = 1 ;
48const short kwxMacAppleMenuId = 1 ;
49
de5914a1
SC
50
51// Find an item given the Macintosh Menu Reference
52
53wxList wxWinMacMenuList(wxKEY_INTEGER);
54wxMenu *wxFindMenuFromMacMenu(MenuRef inMenuRef)
55{
56 wxNode *node = wxWinMacMenuList.Find((long)inMenuRef);
57 if (!node)
58 return NULL;
59 return (wxMenu *)node->GetData();
60}
61
62void wxAssociateMenuWithMacMenu(MenuRef inMenuRef, wxMenu *menu) ;
63void wxAssociateMenuWithMacMenu(MenuRef inMenuRef, wxMenu *menu)
64{
65 // adding NULL MenuRef is (first) surely a result of an error and
66 // (secondly) breaks menu command processing
67 wxCHECK_RET( inMenuRef != (MenuRef) NULL, wxT("attempt to add a NULL MenuRef to menu list") );
68
69 if ( !wxWinMacMenuList.Find((long)inMenuRef) )
70 wxWinMacMenuList.Append((long)inMenuRef, menu);
71}
72
73void wxRemoveMacMenuAssociation(wxMenu *menu) ;
74void wxRemoveMacMenuAssociation(wxMenu *menu)
75{
76 wxWinMacMenuList.DeleteObject(menu);
77}
78
79
e9576ca5
SC
80// ============================================================================
81// implementation
82// ============================================================================
7c15086c
SC
83static void wxMenubarUnsetInvokingWindow( wxMenu *menu ) ;
84static void wxMenubarSetInvokingWindow( wxMenu *menu, wxWindow *win );
519cb848 85
e9576ca5
SC
86// Menus
87
88// Construct a menu with optional title (then use append)
519cb848 89
f5c6eb5c 90#ifdef __DARWIN__
82ca6dbc
GD
91short wxMenu::s_macNextMenuId = 3 ;
92#else
519cb848 93short wxMenu::s_macNextMenuId = 2 ;
82ca6dbc 94#endif
519cb848 95
e7549107 96void wxMenu::Init()
e9576ca5 97{
e7549107 98 m_doBreak = FALSE;
7c15086c 99 m_startRadioGroup = -1;
e7549107
SC
100
101 // create the menu
58751a86 102 m_macMenuId = s_macNextMenuId++;
a9412f8f 103 m_hMenu = UMANewMenu(m_macMenuId, m_title, wxFont::GetDefaultEncoding() );
e7549107
SC
104
105 if ( !m_hMenu )
106 {
22026088 107 wxLogLastError(wxT("UMANewMenu failed"));
e7549107
SC
108 }
109
de5914a1
SC
110 wxAssociateMenuWithMacMenu( (MenuRef)m_hMenu , this ) ;
111
e7549107
SC
112 // if we have a title, insert it in the beginning of the menu
113 if ( !!m_title )
e9576ca5 114 {
519cb848 115 Append(idMenuTitle, m_title) ;
e9576ca5
SC
116 AppendSeparator() ;
117 }
e7549107 118}
e9576ca5 119
e7549107
SC
120wxMenu::~wxMenu()
121{
de5914a1 122 wxRemoveMacMenuAssociation( this ) ;
e40298d5
JS
123 if (MAC_WXHMENU(m_hMenu))
124 ::DisposeMenu(MAC_WXHMENU(m_hMenu));
e9576ca5
SC
125}
126
e7549107 127void wxMenu::Break()
e9576ca5 128{
e40298d5 129 // not available on the mac platform
e7549107 130}
e9576ca5 131
7c15086c 132void wxMenu::Attach(wxMenuBarBase *menubar)
e7549107 133{
7c15086c 134 wxMenuBase::Attach(menubar);
e7549107 135
7c15086c 136 EndRadioGroup();
e9576ca5
SC
137}
138
e9576ca5 139// function appends a new item or submenu to the menu
e7549107
SC
140// append a new item or submenu to the menu
141bool wxMenu::DoInsertOrAppend(wxMenuItem *pItem, size_t pos)
e9576ca5 142{
427ff662 143 wxASSERT_MSG( pItem != NULL, wxT("can't append NULL item to the menu") );
e9576ca5 144
e40298d5
JS
145 if ( pItem->IsSeparator() )
146 {
147 if ( pos == (size_t)-1 )
148 MacAppendMenu(MAC_WXHMENU(m_hMenu), "\p-");
149 else
150 MacInsertMenuItem(MAC_WXHMENU(m_hMenu), "\p-" , pos);
151 }
58751a86 152 else
e40298d5
JS
153 {
154 wxMenu *pSubMenu = pItem->GetSubMenu() ;
155 if ( pSubMenu != NULL )
156 {
427ff662 157 wxASSERT_MSG( pSubMenu->m_hMenu != NULL , wxT("invalid submenu added"));
e40298d5 158 pSubMenu->m_menuParent = this ;
58751a86 159
4224f059 160 if (wxMenuBar::MacGetInstalledMenuBar() == GetMenuBar())
d46342af
SC
161 {
162 pSubMenu->MacBeforeDisplay( true ) ;
163 }
58751a86 164
e40298d5 165 if ( pos == (size_t)-1 )
a9412f8f 166 UMAAppendSubMenuItem(MAC_WXHMENU(m_hMenu), pItem->GetText(), wxFont::GetDefaultEncoding() , pSubMenu->m_macMenuId);
e40298d5 167 else
a9412f8f 168 UMAInsertSubMenuItem(MAC_WXHMENU(m_hMenu), pItem->GetText(), wxFont::GetDefaultEncoding() , pos, pSubMenu->m_macMenuId);
e40298d5
JS
169 pItem->UpdateItemBitmap() ;
170 pItem->UpdateItemStatus() ;
171 }
172 else
173 {
174 if ( pos == (size_t)-1 )
175 {
a9412f8f 176 UMAAppendMenuItem(MAC_WXHMENU(m_hMenu), wxT("a") , wxFont::GetDefaultEncoding() );
e40298d5
JS
177 pos = CountMenuItems(MAC_WXHMENU(m_hMenu)) ;
178 }
179 else
180 {
4ab107d7
SC
181 // MacOS counts menu items from 1 and inserts after, therefore having the
182 // same effect as wx 0 based and inserting before, we must correct pos
183 // after however for updates to be correct
a9412f8f 184 UMAInsertMenuItem(MAC_WXHMENU(m_hMenu), wxT("a"), wxFont::GetDefaultEncoding(), pos);
4ab107d7 185 pos += 1 ;
e40298d5
JS
186 }
187
4ab107d7 188 SetMenuItemCommandID( MAC_WXHMENU(m_hMenu) , pos , pItem->GetId() ) ;
de5914a1 189 SetMenuItemRefCon( MAC_WXHMENU(m_hMenu) , pos , (UInt32) pItem ) ;
e40298d5
JS
190 pItem->UpdateItemText() ;
191 pItem->UpdateItemBitmap() ;
192 pItem->UpdateItemStatus() ;
193
58751a86 194 if ( pItem->GetId() == idMenuTitle )
e40298d5
JS
195 {
196 UMAEnableMenuItem(MAC_WXHMENU(m_hMenu) , pos , false ) ;
197 }
198 }
199 }
e7549107
SC
200 // if we're already attached to the menubar, we must update it
201 if ( IsAttached() )
202 {
4224f059 203 GetMenuBar()->Refresh();
e7549107 204 }
e40298d5 205 return TRUE ;
e9576ca5
SC
206}
207
7c15086c
SC
208void wxMenu::EndRadioGroup()
209{
210 // we're not inside a radio group any longer
211 m_startRadioGroup = -1;
212}
213
9add9367 214wxMenuItem* wxMenu::DoAppend(wxMenuItem *item)
e9576ca5 215{
9add9367 216 wxCHECK_MSG( item, NULL, _T("NULL item in wxMenu::DoAppend") );
7c15086c
SC
217
218 bool check = FALSE;
219
220 if ( item->GetKind() == wxITEM_RADIO )
221 {
222 int count = GetMenuItemCount();
223
224 if ( m_startRadioGroup == -1 )
225 {
226 // start a new radio group
227 m_startRadioGroup = count;
228
229 // for now it has just one element
230 item->SetAsRadioGroupStart();
231 item->SetRadioGroupEnd(m_startRadioGroup);
232
233 // ensure that we have a checked item in the radio group
234 check = TRUE;
235 }
236 else // extend the current radio group
237 {
238 // we need to update its end item
239 item->SetRadioGroupStart(m_startRadioGroup);
240 wxMenuItemList::Node *node = GetMenuItems().Item(m_startRadioGroup);
241
242 if ( node )
243 {
244 node->GetData()->SetRadioGroupEnd(count);
245 }
246 else
247 {
248 wxFAIL_MSG( _T("where is the radio group start item?") );
249 }
250 }
251 }
252 else // not a radio item
253 {
254 EndRadioGroup();
255 }
256
257 if ( !wxMenuBase::DoAppend(item) || !DoInsertOrAppend(item) )
258 {
9add9367 259 return NULL;
7c15086c
SC
260 }
261
262 if ( check )
263 {
264 // check the item initially
265 item->Check(TRUE);
266 }
267
9add9367 268 return item;
e9576ca5
SC
269}
270
9add9367 271wxMenuItem* wxMenu::DoInsert(size_t pos, wxMenuItem *item)
e9576ca5 272{
9add9367
RD
273 if (wxMenuBase::DoInsert(pos, item) && DoInsertOrAppend(item, pos))
274 return item;
275 else
276 return NULL;
e9576ca5
SC
277}
278
e7549107 279wxMenuItem *wxMenu::DoRemove(wxMenuItem *item)
e9576ca5 280{
e7549107
SC
281 // we need to find the items position in the child list
282 size_t pos;
283 wxMenuItemList::Node *node = GetMenuItems().GetFirst();
284 for ( pos = 0; node; pos++ )
285 {
286 if ( node->GetData() == item )
287 break;
e9576ca5 288
e7549107 289 node = node->GetNext();
e9576ca5
SC
290 }
291
e7549107
SC
292 // DoRemove() (unlike Remove) can only be called for existing item!
293 wxCHECK_MSG( node, NULL, wxT("bug in wxMenu::Remove logic") );
519cb848 294
e40298d5 295 ::DeleteMenuItem(MAC_WXHMENU(m_hMenu) , pos + 1);
e9576ca5 296
e7549107
SC
297 if ( IsAttached() )
298 {
7c15086c 299 // otherwise, the change won't be visible
4224f059 300 GetMenuBar()->Refresh();
e7549107 301 }
e9576ca5 302
e7549107
SC
303 // and from internal data structures
304 return wxMenuBase::DoRemove(item);
e9576ca5
SC
305}
306
e9576ca5
SC
307void wxMenu::SetTitle(const wxString& label)
308{
e40298d5 309 m_title = label ;
a9412f8f 310 UMASetMenuTitle(MAC_WXHMENU(m_hMenu) , label , wxFont::GetDefaultEncoding() ) ;
e9576ca5 311}
e7549107 312bool wxMenu::ProcessCommand(wxCommandEvent & event)
e9576ca5
SC
313{
314 bool processed = FALSE;
315
e9576ca5
SC
316 // Try the menu's event handler
317 if ( !processed && GetEventHandler())
318 {
e7549107 319 processed = GetEventHandler()->ProcessEvent(event);
e9576ca5 320 }
519cb848 321
e7549107
SC
322 // Try the window the menu was popped up from (and up through the
323 // hierarchy)
324 wxWindow *win = GetInvokingWindow();
325 if ( !processed && win )
326 processed = win->GetEventHandler()->ProcessEvent(event);
327
328 return processed;
329}
330
331
332// ---------------------------------------------------------------------------
333// other
334// ---------------------------------------------------------------------------
335
e7549107
SC
336wxWindow *wxMenu::GetWindow() const
337{
338 if ( m_invokingWindow != NULL )
339 return m_invokingWindow;
4224f059
DE
340 else if ( GetMenuBar() != NULL)
341 return (wxWindow *) GetMenuBar()->GetFrame();
e7549107
SC
342
343 return NULL;
344}
519cb848 345
58751a86 346// helper functions returning the mac menu position for a certain item, note that this is
519cb848
SC
347// mac-wise 1 - based, i.e. the first item has index 1 whereas on MSWin it has pos 0
348
58751a86 349int wxMenu::MacGetIndexFromId( int id )
519cb848 350{
e7549107
SC
351 size_t pos;
352 wxMenuItemList::Node *node = GetMenuItems().GetFirst();
353 for ( pos = 0; node; pos++ )
519cb848 354 {
e7549107
SC
355 if ( node->GetData()->GetId() == id )
356 break;
519cb848 357
e7549107
SC
358 node = node->GetNext();
359 }
58751a86 360
519cb848 361 if (!node)
e40298d5 362 return 0;
58751a86 363
e40298d5 364 return pos + 1 ;
519cb848
SC
365}
366
58751a86 367int wxMenu::MacGetIndexFromItem( wxMenuItem *pItem )
519cb848 368{
e7549107
SC
369 size_t pos;
370 wxMenuItemList::Node *node = GetMenuItems().GetFirst();
371 for ( pos = 0; node; pos++ )
519cb848 372 {
e7549107
SC
373 if ( node->GetData() == pItem )
374 break;
375
376 node = node->GetNext();
519cb848
SC
377 }
378
379 if (!node)
e40298d5 380 return 0;
58751a86 381
e40298d5 382 return pos + 1 ;
519cb848
SC
383}
384
58751a86 385void wxMenu::MacEnableMenu( bool bDoEnable )
519cb848 386{
e40298d5 387 UMAEnableMenuItem(MAC_WXHMENU(m_hMenu) , 0 , bDoEnable ) ;
58751a86 388
e40298d5 389 ::DrawMenuBar() ;
519cb848
SC
390}
391
d46342af
SC
392// MacOS needs to know about submenus somewhere within this menu
393// before it can be displayed , also hide special menu items like preferences
394// that are handled by the OS
58751a86 395void wxMenu::MacBeforeDisplay( bool isSubMenu )
d46342af
SC
396{
397 wxMenuItem* previousItem = NULL ;
5be55d56 398 size_t pos ;
d46342af
SC
399 wxMenuItemList::Node *node;
400 wxMenuItem *item;
58751a86 401 for (pos = 0, node = GetMenuItems().GetFirst(); node; node = node->GetNext(), pos++)
d46342af
SC
402 {
403 item = (wxMenuItem *)node->GetData();
404 wxMenu* subMenu = item->GetSubMenu() ;
58751a86 405 if (subMenu)
d46342af
SC
406 {
407 subMenu->MacBeforeDisplay( true ) ;
408 }
fa4a6942 409 else // normal item
d46342af
SC
410 {
411 #if TARGET_CARBON
412 if ( UMAGetSystemVersion() >= 0x1000 )
413 {
fa4a6942
VZ
414 // what we do here is to hide the special items which are
415 // shown in the application menu anyhow -- it doesn't make
416 // sense to show them in their normal place as well
417 if ( item->GetId() == wxApp::s_macPreferencesMenuItemId ||
418 item->GetId() == wxApp::s_macExitMenuItemId )
d46342af 419 {
fa4a6942
VZ
420 ChangeMenuItemAttributes( MAC_WXHMENU( GetHMenu() ),
421 pos + 1, kMenuItemAttrHidden, 0 );
422
423 // also check for a separator which was used just to
424 // separate this item from the others, so don't leave
425 // separator at the menu start or end nor 2 consecutive
426 // separators
427 wxMenuItemList::Node *nextNode = node->GetNext();
428 wxMenuItem *next = nextNode ? nextNode->GetData() : NULL;
429
430 size_t posSeptoHide;
431 if ( !previousItem && next && next->IsSeparator() )
432 {
433 // next (i.e. second as we must be first) item is
434 // the separator to hide
435 wxASSERT_MSG( pos == 0, _T("should be the menu start") );
436 posSeptoHide = 2;
437 }
438 else if ( GetMenuItems().GetCount() == pos + 1 &&
439 previousItem != NULL &&
440 previousItem->IsSeparator() )
441 {
442 // prev item is a trailing separator we want to hide
443 posSeptoHide = pos;
444 }
445 else if ( previousItem && previousItem->IsSeparator() &&
446 next && next->IsSeparator() )
447 {
448 // two consecutive separators, this is one too many
449 posSeptoHide = pos;
450 }
451 else // no separators to hide
452 {
453 posSeptoHide = 0;
454 }
455
456 if ( posSeptoHide )
d46342af 457 {
fa4a6942
VZ
458 // hide the separator as well
459 ChangeMenuItemAttributes( MAC_WXHMENU( GetHMenu() ),
460 posSeptoHide,
461 kMenuItemAttrHidden,
462 0 );
d46342af
SC
463 }
464 }
465 }
fa4a6942 466 #endif // TARGET_CARBON
d46342af
SC
467 }
468 previousItem = item ;
469 }
470
471 if ( isSubMenu )
472 ::InsertMenu(MAC_WXHMENU( GetHMenu()), -1);
473
474}
475// undo all changes from the MacBeforeDisplay call
58751a86 476void wxMenu::MacAfterDisplay( bool isSubMenu )
d46342af
SC
477{
478 if ( isSubMenu )
479 ::DeleteMenu(MacGetMenuId());
480
481 wxMenuItem* previousItem = NULL ;
482 int pos ;
483 wxMenuItemList::Node *node;
484 wxMenuItem *item;
58751a86 485 for (pos = 0, node = GetMenuItems().GetFirst(); node; node = node->GetNext(), pos++)
d46342af
SC
486 {
487 item = (wxMenuItem *)node->GetData();
488 wxMenu* subMenu = item->GetSubMenu() ;
58751a86 489 if (subMenu)
d46342af
SC
490 {
491 subMenu->MacAfterDisplay( true ) ;
492 }
493 else
494 {
495 // no need to undo hidings
496 }
497 previousItem = item ;
498 }
499}
500
e9576ca5 501// Menu Bar
519cb848 502
58751a86 503/*
519cb848
SC
504
505Mac Implementation note :
506
507The Mac has only one global menubar, so we attempt to install the currently
508active menubar from a frame, we currently don't take into account mdi-frames
509which would ask for menu-merging
510
58751a86 511Secondly there is no mac api for changing a menubar that is not the current
519cb848
SC
512menubar, so we have to wait for preparing the actual menubar until the
513wxMenubar is to be used
514
58751a86 515We can in subsequent versions use MacInstallMenuBar to provide some sort of
519cb848
SC
516auto-merge for MDI in case this will be necessary
517
518*/
519
520wxMenuBar* wxMenuBar::s_macInstalledMenuBar = NULL ;
1b1d2207 521wxMenuBar* wxMenuBar::s_macCommonMenuBar = NULL ;
519cb848 522
e7549107 523void wxMenuBar::Init()
e9576ca5
SC
524{
525 m_eventHandler = this;
e9576ca5 526 m_menuBarFrame = NULL;
7c15086c 527 m_invokingWindow = (wxWindow*) NULL;
e9576ca5
SC
528}
529
51abe921
SC
530wxMenuBar::wxMenuBar()
531{
532 Init();
533}
534
535wxMenuBar::wxMenuBar( long WXUNUSED(style) )
536{
537 Init();
538}
539
e7549107
SC
540
541wxMenuBar::wxMenuBar(int count, wxMenu *menus[], const wxString titles[])
e9576ca5 542{
e7549107
SC
543 Init();
544
545 m_titles.Alloc(count);
546
547 for ( int i = 0; i < count; i++ )
548 {
549 m_menus.Append(menus[i]);
550 m_titles.Add(titles[i]);
551
552 menus[i]->Attach(this);
553 }
e9576ca5
SC
554}
555
556wxMenuBar::~wxMenuBar()
557{
1b1d2207
DE
558 if (s_macCommonMenuBar == this)
559 s_macCommonMenuBar = NULL;
e40298d5
JS
560 if (s_macInstalledMenuBar == this)
561 {
562 ::ClearMenuBar();
563 s_macInstalledMenuBar = NULL;
564 }
519cb848 565
e7549107
SC
566}
567
6d6da89c 568void wxMenuBar::Refresh(bool WXUNUSED(eraseBackground), const wxRect *WXUNUSED(rect))
e7549107
SC
569{
570 wxCHECK_RET( IsAttached(), wxT("can't refresh unatteched menubar") );
e9576ca5 571
e7549107 572 DrawMenuBar();
e9576ca5
SC
573}
574
58751a86 575void wxMenuBar::MacInstallMenuBar()
519cb848 576{
2b8a6962
GD
577 if ( s_macInstalledMenuBar == this )
578 return ;
58751a86 579
53d92341
SC
580 MenuBarHandle menubar = NULL ;
581#if TARGET_API_MAC_OSX
582 menubar = NewHandleClear( 6 /* sizeof( MenuBarHeader ) */ ) ;
583#else
584 menubar = NewHandleClear( 12 ) ;
585 (*menubar)[3] = 0x0a ;
586#endif
2b8a6962 587 ::SetMenuBar( menubar ) ;
dd05f811 588 DisposeMenuBar( menubar ) ;
cda73c27
SC
589 MenuHandle appleMenu = NULL ;
590 char appleMenuTitle[3] = { 01 , kMenuAppleLogoFilledGlyph , 0 } ;
591
592 verify_noerr( CreateNewMenu( kwxMacAppleMenuId , 0 , &appleMenu ) ) ;
593 verify_noerr( SetMenuTitle( appleMenu , (ConstStr255Param) appleMenuTitle ) );
23c6ddc8 594
262ce38a
KH
595 // Add About/Preferences separator only on OS X
596 // KH/RN: Separator is always present on 10.3 but not on 10.2
597 // However, the change from 10.2 to 10.3 suggests it is preferred
598#if TARGET_API_MAC_OSX
e957d41c 599 MacInsertMenuItem( appleMenu , "\p-" , 0 ) ;
262ce38a
KH
600#endif
601
cda73c27
SC
602 MacInsertMenuItem( appleMenu , "\pAbout..." , 0 ) ;
603 MacInsertMenu( appleMenu , 0 ) ;
604
7c15086c 605 // clean-up the help menu before adding new items
e40298d5
JS
606 MenuHandle mh = NULL ;
607 if ( UMAGetHelpMenu( &mh , &firstUserHelpMenuItem) == noErr )
608 {
609 for ( int i = CountMenuItems( mh ) ; i >= firstUserHelpMenuItem ; --i )
610 {
611 DeleteMenuItem( mh , i ) ;
612 }
613 }
614 else
615 {
616 mh = NULL ;
617 }
7c15086c 618#if TARGET_CARBON
e40298d5
JS
619 if ( UMAGetSystemVersion() >= 0x1000 && wxApp::s_macPreferencesMenuItemId)
620 {
621 wxMenuItem *item = FindItem( wxApp::s_macPreferencesMenuItemId , NULL ) ;
622 if ( item == NULL || !(item->IsEnabled()) )
623 DisableMenuCommand( NULL , kHICommandPreferences ) ;
624 else
625 EnableMenuCommand( NULL , kHICommandPreferences ) ;
626 }
7c15086c 627#endif
e40298d5
JS
628 for (size_t i = 0; i < m_menus.GetCount(); i++)
629 {
f823cacb 630 wxMenuItemList::Node *node;
2b5f62a0
VZ
631 wxMenuItem *item;
632 int pos ;
e40298d5
JS
633 wxMenu* menu = m_menus[i] , *subMenu = NULL ;
634
427ff662 635 if( m_titles[i] == wxT("?") || m_titles[i] == wxT("&?") || m_titles[i] == wxApp::s_macHelpMenuTitleName )
e40298d5
JS
636 {
637 if ( mh == NULL )
638 {
639 continue ;
640 }
58751a86
RD
641
642 for (pos = 0 , node = menu->GetMenuItems().GetFirst(); node; node = node->GetNext(), pos++)
e40298d5
JS
643 {
644 item = (wxMenuItem *)node->GetData();
645 subMenu = item->GetSubMenu() ;
58751a86 646 if (subMenu)
e40298d5
JS
647 {
648 // we don't support hierarchical menus in the help menu yet
649 }
58751a86 650 else
e40298d5
JS
651 {
652 if ( item->IsSeparator() )
653 {
654 if ( mh )
655 MacAppendMenu(mh, "\p-" );
656 }
657 else
658 {
659 wxAcceleratorEntry* entry = wxGetAccelFromString( item->GetText() ) ;
660
661 if ( item->GetId() == wxApp::s_macAboutMenuItemId )
58751a86 662 {
a9412f8f 663 UMASetMenuItemText( GetMenuHandle( kwxMacAppleMenuId ) , 1 , item->GetText() , wxFont::GetDefaultEncoding() );
e40298d5
JS
664 UMAEnableMenuItem( GetMenuHandle( kwxMacAppleMenuId ) , 1 , true );
665 SetMenuItemCommandID( GetMenuHandle( kwxMacAppleMenuId ) , 1 , item->GetId() ) ;
de5914a1 666 SetMenuItemRefCon(GetMenuHandle( kwxMacAppleMenuId ) , 1 , (UInt32)item ) ;
e40298d5
JS
667 UMASetMenuItemShortcut( GetMenuHandle( kwxMacAppleMenuId ) , 1 , entry ) ;
668 }
669 else
670 {
671 if ( mh )
672 {
a9412f8f 673 UMAAppendMenuItem(mh, item->GetText() , wxFont::GetDefaultEncoding(), entry);
e40298d5 674 SetMenuItemCommandID( mh , CountMenuItems(mh) , item->GetId() ) ;
de5914a1 675 SetMenuItemRefCon( mh , CountMenuItems(mh) , (UInt32)item ) ;
e40298d5
JS
676 }
677 }
58751a86 678
e40298d5
JS
679 delete entry ;
680 }
681 }
682 }
683 }
684 else
685 {
a9412f8f 686 UMASetMenuTitle( MAC_WXHMENU(menu->GetHMenu()) , m_titles[i], m_font.GetEncoding() ) ;
d46342af 687 m_menus[i]->MacBeforeDisplay(false) ;
e40298d5 688 ::InsertMenu(MAC_WXHMENU(m_menus[i]->GetHMenu()), 0);
e40298d5
JS
689 }
690 }
691 ::DrawMenuBar() ;
692 s_macInstalledMenuBar = this;
519cb848
SC
693}
694
e7549107 695void wxMenuBar::EnableTop(size_t pos, bool enable)
e9576ca5 696{
e7549107 697 wxCHECK_RET( IsAttached(), wxT("doesn't work with unattached menubars") );
e40298d5 698 m_menus[pos]->MacEnableMenu( enable ) ;
e7549107 699 Refresh();
e9576ca5
SC
700}
701
c393c740
JS
702bool wxMenuBar::Enable( bool enable)
703{
5059f192 704 wxCHECK_MSG( IsAttached(), false, wxT("doesn't work with unattached menubars") );
c393c740
JS
705 size_t i;
706 for (i = 0; i < GetMenuCount(); i++)
707 {
708 EnableTop(i, enable);
709 }
710 return true;
711}
712
e7549107 713void wxMenuBar::SetLabelTop(size_t pos, const wxString& label)
e9576ca5 714{
e7549107 715 wxCHECK_RET( pos < GetMenuCount(), wxT("invalid menu index") );
e9576ca5 716
e7549107 717 m_titles[pos] = label;
e9576ca5 718
e7549107
SC
719 if ( !IsAttached() )
720 {
e9576ca5 721 return;
e7549107 722 }
e9576ca5 723
519cb848 724 m_menus[pos]->SetTitle( label ) ;
e40298d5
JS
725 if (wxMenuBar::s_macInstalledMenuBar == this) // are we currently installed ?
726 {
727 ::SetMenuBar( GetMenuBar() ) ;
728 ::InvalMenuBar() ;
729 }
e9576ca5
SC
730}
731
e7549107 732wxString wxMenuBar::GetLabelTop(size_t pos) const
e9576ca5 733{
e7549107
SC
734 wxCHECK_MSG( pos < GetMenuCount(), wxEmptyString,
735 wxT("invalid menu index in wxMenuBar::GetLabelTop") );
519cb848 736
e7549107 737 return m_titles[pos];
e9576ca5
SC
738}
739
e7549107 740int wxMenuBar::FindMenu(const wxString& title)
e9576ca5 741{
e7549107 742 wxString menuTitle = wxStripMenuCodes(title);
e9576ca5 743
e7549107
SC
744 size_t count = GetMenuCount();
745 for ( size_t i = 0; i < count; i++ )
e9576ca5 746 {
e7549107
SC
747 wxString title = wxStripMenuCodes(m_titles[i]);
748 if ( menuTitle == title )
58751a86 749 return i;
e9576ca5 750 }
e9576ca5 751
e7549107 752 return wxNOT_FOUND;
e9576ca5 753
e9576ca5
SC
754}
755
e7549107
SC
756
757// ---------------------------------------------------------------------------
758// wxMenuBar construction
759// ---------------------------------------------------------------------------
760
761// ---------------------------------------------------------------------------
762// wxMenuBar construction
763// ---------------------------------------------------------------------------
764
765wxMenu *wxMenuBar::Replace(size_t pos, wxMenu *menu, const wxString& title)
e9576ca5 766{
e7549107
SC
767 wxMenu *menuOld = wxMenuBarBase::Replace(pos, menu, title);
768 if ( !menuOld )
769 return FALSE;
770 m_titles[pos] = title;
e9576ca5 771
e7549107 772 if ( IsAttached() )
e9576ca5 773 {
e40298d5
JS
774 if (s_macInstalledMenuBar == this)
775 {
d46342af 776 menuOld->MacAfterDisplay( false ) ;
e40298d5
JS
777 ::DeleteMenu( menuOld->MacGetMenuId() /* m_menus[pos]->MacGetMenuId() */ ) ;
778 {
d46342af 779 menu->MacBeforeDisplay( false ) ;
a9412f8f 780 UMASetMenuTitle( MAC_WXHMENU(menu->GetHMenu()) , title , m_font.GetEncoding() ) ;
e40298d5
JS
781 if ( pos == m_menus.GetCount() - 1)
782 {
783 ::InsertMenu( MAC_WXHMENU(menu->GetHMenu()) , 0 ) ;
784 }
785 else
786 {
787 ::InsertMenu( MAC_WXHMENU(menu->GetHMenu()) , m_menus[pos+1]->MacGetMenuId() ) ;
788 }
789 }
790 }
e9576ca5 791
e7549107 792 Refresh();
e9576ca5 793 }
e9576ca5 794
e7549107 795 return menuOld;
e9576ca5
SC
796}
797
e7549107 798bool wxMenuBar::Insert(size_t pos, wxMenu *menu, const wxString& title)
e9576ca5 799{
e7549107
SC
800 if ( !wxMenuBarBase::Insert(pos, menu, title) )
801 return FALSE;
e9576ca5 802
e7549107 803 m_titles.Insert(title, pos);
e9576ca5 804
a9412f8f 805 UMASetMenuTitle( MAC_WXHMENU(menu->GetHMenu()) , title , m_font.GetEncoding() ) ;
e7549107 806
d46342af 807 if ( IsAttached() && s_macInstalledMenuBar == this )
e9576ca5 808 {
d46342af 809 if (s_macInstalledMenuBar == this)
e40298d5 810 {
d46342af
SC
811 menu->MacBeforeDisplay( false ) ;
812 if ( pos == (size_t) -1 || pos + 1 == m_menus.GetCount() )
813 {
814 ::InsertMenu( MAC_WXHMENU(menu->GetHMenu()) , 0 ) ;
815 }
816 else
817 {
818 ::InsertMenu( MAC_WXHMENU(menu->GetHMenu()) , m_menus[pos+1]->MacGetMenuId() ) ;
819 }
e40298d5 820 }
e7549107 821 Refresh();
e9576ca5 822 }
e7549107
SC
823
824 return TRUE;
e9576ca5
SC
825}
826
51abe921
SC
827wxMenu *wxMenuBar::Remove(size_t pos)
828{
829 wxMenu *menu = wxMenuBarBase::Remove(pos);
830 if ( !menu )
831 return NULL;
832
833 if ( IsAttached() )
834 {
e40298d5
JS
835 if (s_macInstalledMenuBar == this)
836 {
837 ::DeleteMenu( menu->MacGetMenuId() /* m_menus[pos]->MacGetMenuId() */ ) ;
838 }
51abe921 839
51abe921
SC
840 Refresh();
841 }
842
5fe38474 843 m_titles.RemoveAt(pos);
51abe921
SC
844
845 return menu;
846}
847
848bool wxMenuBar::Append(wxMenu *menu, const wxString& title)
849{
850 WXHMENU submenu = menu ? menu->GetHMenu() : 0;
851 wxCHECK_MSG( submenu, FALSE, wxT("can't append invalid menu to menubar") );
852
853 if ( !wxMenuBarBase::Append(menu, title) )
854 return FALSE;
855
51abe921 856 m_titles.Add(title);
58751a86 857
a9412f8f 858 UMASetMenuTitle( MAC_WXHMENU(menu->GetHMenu()) , title , m_font.GetEncoding() ) ;
51abe921
SC
859
860 if ( IsAttached() )
861 {
e40298d5
JS
862 if (s_macInstalledMenuBar == this)
863 {
864 ::InsertMenu( MAC_WXHMENU(menu->GetHMenu()) , 0 ) ;
865 }
51abe921
SC
866
867 Refresh();
868 }
869
7c15086c
SC
870 // m_invokingWindow is set after wxFrame::SetMenuBar(). This call enables
871 // adding menu later on.
872 if (m_invokingWindow)
873 wxMenubarSetInvokingWindow( menu, m_invokingWindow );
874
51abe921
SC
875 return TRUE;
876}
877
2b5f62a0
VZ
878static void wxMenubarUnsetInvokingWindow( wxMenu *menu )
879{
880 menu->SetInvokingWindow( (wxWindow*) NULL );
881
882 wxMenuItemList::Node *node = menu->GetMenuItems().GetFirst();
883 while (node)
884 {
885 wxMenuItem *menuitem = node->GetData();
886 if (menuitem->IsSubMenu())
887 wxMenubarUnsetInvokingWindow( menuitem->GetSubMenu() );
888 node = node->GetNext();
889 }
890}
891
892static void wxMenubarSetInvokingWindow( wxMenu *menu, wxWindow *win )
893{
894 menu->SetInvokingWindow( win );
895
896 wxMenuItemList::Node *node = menu->GetMenuItems().GetFirst();
897 while (node)
898 {
899 wxMenuItem *menuitem = node->GetData();
900 if (menuitem->IsSubMenu())
901 wxMenubarSetInvokingWindow( menuitem->GetSubMenu() , win );
902 node = node->GetNext();
903 }
904}
905
906void wxMenuBar::UnsetInvokingWindow()
907{
7c15086c 908 m_invokingWindow = (wxWindow*) NULL;
2b5f62a0
VZ
909 wxMenuList::Node *node = m_menus.GetFirst();
910 while (node)
911 {
912 wxMenu *menu = node->GetData();
913 wxMenubarUnsetInvokingWindow( menu );
914 node = node->GetNext();
915 }
916}
917
918void wxMenuBar::SetInvokingWindow(wxFrame *frame)
919{
7c15086c 920 m_invokingWindow = frame;
2b5f62a0
VZ
921 wxMenuList::Node *node = m_menus.GetFirst();
922 while (node)
923 {
924 wxMenu *menu = node->GetData();
925 wxMenubarSetInvokingWindow( menu, frame );
926 node = node->GetNext();
927 }
928}
929
90b959ae 930void wxMenuBar::Detach()
2f1ae414 931{
90b959ae
SC
932 wxMenuBarBase::Detach() ;
933}
2f1ae414 934
90b959ae
SC
935void wxMenuBar::Attach(wxFrame *frame)
936{
937 wxMenuBarBase::Attach( frame ) ;
2f1ae414 938}
51abe921
SC
939// ---------------------------------------------------------------------------
940// wxMenuBar searching for menu items
941// ---------------------------------------------------------------------------
942
943// Find the itemString in menuString, and return the item id or wxNOT_FOUND
944int wxMenuBar::FindMenuItem(const wxString& menuString,
945 const wxString& itemString) const
946{
947 wxString menuLabel = wxStripMenuCodes(menuString);
948 size_t count = GetMenuCount();
949 for ( size_t i = 0; i < count; i++ )
950 {
951 wxString title = wxStripMenuCodes(m_titles[i]);
ef089805 952 if ( menuLabel == title )
51abe921
SC
953 return m_menus[i]->FindItem(itemString);
954 }
955
956 return wxNOT_FOUND;
957}
958
959wxMenuItem *wxMenuBar::FindItem(int id, wxMenu **itemMenu) const
960{
961 if ( itemMenu )
962 *itemMenu = NULL;
963
964 wxMenuItem *item = NULL;
965 size_t count = GetMenuCount();
966 for ( size_t i = 0; !item && (i < count); i++ )
967 {
968 item = m_menus[i]->FindItem(id, itemMenu);
969 }
970
971 return item;
972}
973
974