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