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