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