]> git.saurik.com Git - wxWidgets.git/blame_incremental - src/mac/carbon/menu.cpp
Base for wxMessageDialog with common checks for style.
[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
40#if !USE_SHARED_LIBRARY
41IMPLEMENT_DYNAMIC_CLASS(wxMenu, wxEvtHandler)
42IMPLEMENT_DYNAMIC_CLASS(wxMenuBar, wxEvtHandler)
43#endif
44
45// the (popup) menu title has this special id
46static const int idMenuTitle = -3;
47static MenuItemIndex firstUserHelpMenuItem = 0 ;
48
49const short kwxMacMenuBarResource = 1 ;
50const short kwxMacAppleMenuId = 1 ;
51
52
53// Find an item given the Macintosh Menu Reference
54
55#if KEY_wxList_DEPRECATED
56wxList wxWinMacMenuList(wxKEY_INTEGER);
57wxMenu *wxFindMenuFromMacMenu(MenuRef inMenuRef)
58{
59 wxNode *node = wxWinMacMenuList.Find((long)inMenuRef);
60 if (!node)
61 return NULL;
62 return (wxMenu *)node->GetData();
63}
64
65void wxAssociateMenuWithMacMenu(MenuRef inMenuRef, wxMenu *menu) ;
66void 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
76void wxRemoveMacMenuAssociation(wxMenu *menu) ;
77void wxRemoveMacMenuAssociation(wxMenu *menu)
78{
79 wxWinMacMenuList.DeleteObject(menu);
80}
81#else
82
83WX_DECLARE_HASH_MAP(MenuRef, wxMenu*, wxPointerHash, wxPointerEqual, MacMenuMap);
84
85static MacMenuMap wxWinMacMenuList;
86
87wxMenu *wxFindMenuFromMacMenu(MenuRef inMenuRef)
88{
89 MacMenuMap::iterator node = wxWinMacMenuList.find(inMenuRef);
90
91 return (node == wxWinMacMenuList.end()) ? NULL : node->second;
92}
93
94void wxAssociateMenuWithMacMenu(MenuRef inMenuRef, wxMenu *menu) ;
95void 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
104void wxRemoveMacMenuAssociation(wxMenu *menu) ;
105void 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// ============================================================================
123static void wxMenubarUnsetInvokingWindow( wxMenu *menu ) ;
124static void wxMenubarSetInvokingWindow( wxMenu *menu, wxWindow *win );
125
126// Menus
127
128// Construct a menu with optional title (then use append)
129
130#ifdef __DARWIN__
131short wxMenu::s_macNextMenuId = 3 ;
132#else
133short wxMenu::s_macNextMenuId = 2 ;
134#endif
135
136static
137wxMenu *
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
147void 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
171wxMenu::~wxMenu()
172{
173 wxRemoveMacMenuAssociation( this ) ;
174 if (MAC_WXHMENU(m_hMenu))
175 ::DisposeMenu(MAC_WXHMENU(m_hMenu));
176}
177
178void wxMenu::Break()
179{
180 // not available on the mac platform
181}
182
183void 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
192bool 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
259void wxMenu::EndRadioGroup()
260{
261 // we're not inside a radio group any longer
262 m_startRadioGroup = -1;
263}
264
265wxMenuItem* 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
322wxMenuItem* 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
330wxMenuItem *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
358void wxMenu::SetTitle(const wxString& label)
359{
360 m_title = label ;
361 UMASetMenuTitle(MAC_WXHMENU(m_hMenu) , label , wxFont::GetDefaultEncoding() ) ;
362}
363bool 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
387wxWindow *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
400int 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
418int 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
436void 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
446void 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
527void 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
556Mac Implementation note :
557
558The Mac has only one global menubar, so we attempt to install the currently
559active menubar from a frame, we currently don't take into account mdi-frames
560which would ask for menu-merging
561
562Secondly there is no mac api for changing a menubar that is not the current
563menubar, so we have to wait for preparing the actual menubar until the
564wxMenubar is to be used
565
566We can in subsequent versions use MacInstallMenuBar to provide some sort of
567auto-merge for MDI in case this will be necessary
568
569*/
570
571wxMenuBar* wxMenuBar::s_macInstalledMenuBar = NULL ;
572wxMenuBar* wxMenuBar::s_macCommonMenuBar = NULL ;
573
574void wxMenuBar::Init()
575{
576 m_eventHandler = this;
577 m_menuBarFrame = NULL;
578 m_invokingWindow = (wxWindow*) NULL;
579}
580
581wxMenuBar::wxMenuBar()
582{
583 Init();
584}
585
586wxMenuBar::wxMenuBar( long WXUNUSED(style) )
587{
588 Init();
589}
590
591
592wxMenuBar::wxMenuBar(int count, wxMenu *menus[], const wxString titles[])
593{
594 Init();
595
596 m_titles.Alloc(count);
597
598 for ( int i = 0; i < count; i++ )
599 {
600 m_menus.Append(menus[i]);
601 m_titles.Add(titles[i]);
602
603 menus[i]->Attach(this);
604 }
605}
606
607wxMenuBar::~wxMenuBar()
608{
609 if (s_macCommonMenuBar == this)
610 s_macCommonMenuBar = NULL;
611 if (s_macInstalledMenuBar == this)
612 {
613 ::ClearMenuBar();
614 s_macInstalledMenuBar = NULL;
615 }
616
617}
618
619void wxMenuBar::Refresh(bool WXUNUSED(eraseBackground), const wxRect *WXUNUSED(rect))
620{
621 wxCHECK_RET( IsAttached(), wxT("can't refresh unatteched menubar") );
622
623 DrawMenuBar();
624}
625
626void wxMenuBar::MacInstallMenuBar()
627{
628 if ( s_macInstalledMenuBar == this )
629 return ;
630
631 MenuBarHandle menubar = NULL ;
632#if TARGET_API_MAC_OSX
633 menubar = NewHandleClear( 6 /* sizeof( MenuBarHeader ) */ ) ;
634#else
635 menubar = NewHandleClear( 12 ) ;
636 (*menubar)[3] = 0x0a ;
637#endif
638 ::SetMenuBar( menubar ) ;
639 DisposeMenuBar( menubar ) ;
640 MenuHandle appleMenu = NULL ;
641 char appleMenuTitle[3] = { 01 , kMenuAppleLogoFilledGlyph , 0 } ;
642
643 verify_noerr( CreateNewMenu( kwxMacAppleMenuId , 0 , &appleMenu ) ) ;
644 verify_noerr( SetMenuTitle( appleMenu , (ConstStr255Param) appleMenuTitle ) );
645
646 // Add About/Preferences separator only on OS X
647 // KH/RN: Separator is always present on 10.3 but not on 10.2
648 // However, the change from 10.2 to 10.3 suggests it is preferred
649#if TARGET_API_MAC_OSX
650 MacInsertMenuItem( appleMenu , "\p-" , 0 ) ;
651#endif
652
653 MacInsertMenuItem( appleMenu , "\pAbout..." , 0 ) ;
654 MacInsertMenu( appleMenu , 0 ) ;
655
656 // clean-up the help menu before adding new items
657 MenuHandle mh = NULL ;
658 if ( UMAGetHelpMenu( &mh , &firstUserHelpMenuItem) == noErr )
659 {
660 for ( int i = CountMenuItems( mh ) ; i >= firstUserHelpMenuItem ; --i )
661 {
662 DeleteMenuItem( mh , i ) ;
663 }
664 }
665 else
666 {
667 mh = NULL ;
668 }
669#if TARGET_CARBON
670 if ( UMAGetSystemVersion() >= 0x1000 && wxApp::s_macPreferencesMenuItemId)
671 {
672 wxMenuItem *item = FindItem( wxApp::s_macPreferencesMenuItemId , NULL ) ;
673 if ( item == NULL || !(item->IsEnabled()) )
674 DisableMenuCommand( NULL , kHICommandPreferences ) ;
675 else
676 EnableMenuCommand( NULL , kHICommandPreferences ) ;
677 }
678#endif
679 wxMenuList::compatibility_iterator menuIter = m_menus.GetFirst();
680 //
681 for (size_t i = 0; i < m_menus.GetCount(); i++, menuIter = menuIter->GetNext())
682 {
683 wxMenuItemList::compatibility_iterator node;
684 wxMenuItem *item;
685 int pos ;
686 wxMenu* menu = menuIter->GetData() , *subMenu = NULL ;
687
688 if( m_titles[i] == wxT("?") || m_titles[i] == wxT("&?") || m_titles[i] == wxApp::s_macHelpMenuTitleName )
689 {
690 if ( mh == NULL )
691 {
692 continue ;
693 }
694
695 for (pos = 0 , node = menu->GetMenuItems().GetFirst(); node; node = node->GetNext(), pos++)
696 {
697 item = (wxMenuItem *)node->GetData();
698 subMenu = item->GetSubMenu() ;
699 if (subMenu)
700 {
701 // we don't support hierarchical menus in the help menu yet
702 }
703 else
704 {
705 if ( item->IsSeparator() )
706 {
707 if ( mh )
708 MacAppendMenu(mh, "\p-" );
709 }
710 else
711 {
712 wxAcceleratorEntry* entry = wxGetAccelFromString( item->GetText() ) ;
713
714 if ( item->GetId() == wxApp::s_macAboutMenuItemId )
715 {
716 UMASetMenuItemText( GetMenuHandle( kwxMacAppleMenuId ) , 1 , item->GetText() , wxFont::GetDefaultEncoding() );
717 UMAEnableMenuItem( GetMenuHandle( kwxMacAppleMenuId ) , 1 , true );
718 SetMenuItemCommandID( GetMenuHandle( kwxMacAppleMenuId ) , 1 , item->GetId() ) ;
719 SetMenuItemRefCon(GetMenuHandle( kwxMacAppleMenuId ) , 1 , (UInt32)item ) ;
720 UMASetMenuItemShortcut( GetMenuHandle( kwxMacAppleMenuId ) , 1 , entry ) ;
721 }
722 else
723 {
724 if ( mh )
725 {
726 UMAAppendMenuItem(mh, item->GetText() , wxFont::GetDefaultEncoding(), entry);
727 SetMenuItemCommandID( mh , CountMenuItems(mh) , item->GetId() ) ;
728 SetMenuItemRefCon( mh , CountMenuItems(mh) , (UInt32)item ) ;
729 }
730 }
731
732 delete entry ;
733 }
734 }
735 }
736 }
737 else
738 {
739 UMASetMenuTitle( MAC_WXHMENU(menu->GetHMenu()) , m_titles[i], m_font.GetEncoding() ) ;
740 menu->MacBeforeDisplay(false) ;
741 ::InsertMenu(MAC_WXHMENU(_wxMenuAt(m_menus, i)->GetHMenu()), 0);
742 }
743 }
744 ::DrawMenuBar() ;
745 s_macInstalledMenuBar = this;
746}
747
748void wxMenuBar::EnableTop(size_t pos, bool enable)
749{
750 wxCHECK_RET( IsAttached(), wxT("doesn't work with unattached menubars") );
751 _wxMenuAt(m_menus, pos)->MacEnableMenu( enable ) ;
752 Refresh();
753}
754
755bool wxMenuBar::Enable( bool enable)
756{
757 wxCHECK_MSG( IsAttached(), false, wxT("doesn't work with unattached menubars") );
758 size_t i;
759 for (i = 0; i < GetMenuCount(); i++)
760 {
761 EnableTop(i, enable);
762 }
763 return true;
764}
765
766void wxMenuBar::SetLabelTop(size_t pos, const wxString& label)
767{
768 wxCHECK_RET( pos < GetMenuCount(), wxT("invalid menu index") );
769
770 m_titles[pos] = label;
771
772 if ( !IsAttached() )
773 {
774 return;
775 }
776
777 _wxMenuAt(m_menus, pos)->SetTitle( label ) ;
778
779 if (wxMenuBar::s_macInstalledMenuBar == this) // are we currently installed ?
780 {
781 ::SetMenuBar( GetMenuBar() ) ;
782 ::InvalMenuBar() ;
783 }
784}
785
786wxString wxMenuBar::GetLabelTop(size_t pos) const
787{
788 wxCHECK_MSG( pos < GetMenuCount(), wxEmptyString,
789 wxT("invalid menu index in wxMenuBar::GetLabelTop") );
790
791 return m_titles[pos];
792}
793
794int wxMenuBar::FindMenu(const wxString& title)
795{
796 wxString menuTitle = wxStripMenuCodes(title);
797
798 size_t count = GetMenuCount();
799 for ( size_t i = 0; i < count; i++ )
800 {
801 wxString title = wxStripMenuCodes(m_titles[i]);
802 if ( menuTitle == title )
803 return i;
804 }
805
806 return wxNOT_FOUND;
807
808}
809
810
811// ---------------------------------------------------------------------------
812// wxMenuBar construction
813// ---------------------------------------------------------------------------
814
815wxMenu *wxMenuBar::Replace(size_t pos, wxMenu *menu, const wxString& title)
816{
817 wxMenu *menuOld = wxMenuBarBase::Replace(pos, menu, title);
818 if ( !menuOld )
819 return FALSE;
820 m_titles[pos] = title;
821
822 if ( IsAttached() )
823 {
824 if (s_macInstalledMenuBar == this)
825 {
826 menuOld->MacAfterDisplay( false ) ;
827 ::DeleteMenu( menuOld->MacGetMenuId() /* m_menus[pos]->MacGetMenuId() */ ) ;
828 {
829 menu->MacBeforeDisplay( false ) ;
830 UMASetMenuTitle( MAC_WXHMENU(menu->GetHMenu()) , title , m_font.GetEncoding() ) ;
831 if ( pos == m_menus.GetCount() - 1)
832 {
833 ::InsertMenu( MAC_WXHMENU(menu->GetHMenu()) , 0 ) ;
834 }
835 else
836 {
837 ::InsertMenu( MAC_WXHMENU(menu->GetHMenu()) , _wxMenuAt(m_menus, pos+1)->MacGetMenuId() ) ;
838 }
839 }
840 }
841
842 Refresh();
843 }
844 if (m_invokingWindow)
845 wxMenubarSetInvokingWindow( menu, m_invokingWindow );
846
847 return menuOld;
848}
849
850bool wxMenuBar::Insert(size_t pos, wxMenu *menu, const wxString& title)
851{
852 if ( !wxMenuBarBase::Insert(pos, menu, title) )
853 return FALSE;
854
855 m_titles.Insert(title, pos);
856
857 UMASetMenuTitle( MAC_WXHMENU(menu->GetHMenu()) , title , m_font.GetEncoding() ) ;
858
859 if ( IsAttached() && s_macInstalledMenuBar == this )
860 {
861 if (s_macInstalledMenuBar == this)
862 {
863 menu->MacBeforeDisplay( false ) ;
864 if ( pos == (size_t) -1 || pos + 1 == m_menus.GetCount() )
865 {
866 ::InsertMenu( MAC_WXHMENU(menu->GetHMenu()) , 0 ) ;
867 }
868 else
869 {
870 ::InsertMenu( MAC_WXHMENU(menu->GetHMenu()) , _wxMenuAt(m_menus, pos+1)->MacGetMenuId() ) ;
871 }
872 }
873 Refresh();
874 }
875 if (m_invokingWindow)
876 wxMenubarSetInvokingWindow( menu, m_invokingWindow );
877
878 return TRUE;
879}
880
881wxMenu *wxMenuBar::Remove(size_t pos)
882{
883 wxMenu *menu = wxMenuBarBase::Remove(pos);
884 if ( !menu )
885 return NULL;
886
887 if ( IsAttached() )
888 {
889 if (s_macInstalledMenuBar == this)
890 {
891 ::DeleteMenu( menu->MacGetMenuId() /* m_menus[pos]->MacGetMenuId() */ ) ;
892 }
893
894 Refresh();
895 }
896
897 m_titles.RemoveAt(pos);
898
899 return menu;
900}
901
902bool wxMenuBar::Append(wxMenu *menu, const wxString& title)
903{
904 WXHMENU submenu = menu ? menu->GetHMenu() : 0;
905 wxCHECK_MSG( submenu, FALSE, wxT("can't append invalid menu to menubar") );
906
907 if ( !wxMenuBarBase::Append(menu, title) )
908 return FALSE;
909
910 m_titles.Add(title);
911
912 UMASetMenuTitle( MAC_WXHMENU(menu->GetHMenu()) , title , m_font.GetEncoding() ) ;
913
914 if ( IsAttached() )
915 {
916 if (s_macInstalledMenuBar == this)
917 {
918 menu->MacBeforeDisplay( false ) ;
919 ::InsertMenu( MAC_WXHMENU(menu->GetHMenu()) , 0 ) ;
920 }
921
922 Refresh();
923 }
924
925 // m_invokingWindow is set after wxFrame::SetMenuBar(). This call enables
926 // adding menu later on.
927 if (m_invokingWindow)
928 wxMenubarSetInvokingWindow( menu, m_invokingWindow );
929
930 return TRUE;
931}
932
933static void wxMenubarUnsetInvokingWindow( wxMenu *menu )
934{
935 menu->SetInvokingWindow( (wxWindow*) NULL );
936
937 wxMenuItemList::compatibility_iterator node = menu->GetMenuItems().GetFirst();
938 while (node)
939 {
940 wxMenuItem *menuitem = node->GetData();
941 if (menuitem->IsSubMenu())
942 wxMenubarUnsetInvokingWindow( menuitem->GetSubMenu() );
943 node = node->GetNext();
944 }
945}
946
947static void wxMenubarSetInvokingWindow( wxMenu *menu, wxWindow *win )
948{
949 menu->SetInvokingWindow( win );
950
951 wxMenuItemList::compatibility_iterator node = menu->GetMenuItems().GetFirst();
952 while (node)
953 {
954 wxMenuItem *menuitem = node->GetData();
955 if (menuitem->IsSubMenu())
956 wxMenubarSetInvokingWindow( menuitem->GetSubMenu() , win );
957 node = node->GetNext();
958 }
959}
960
961void wxMenuBar::UnsetInvokingWindow()
962{
963 m_invokingWindow = (wxWindow*) NULL;
964 wxMenuList::compatibility_iterator node = m_menus.GetFirst();
965 while (node)
966 {
967 wxMenu *menu = node->GetData();
968 wxMenubarUnsetInvokingWindow( menu );
969 node = node->GetNext();
970 }
971}
972
973void wxMenuBar::SetInvokingWindow(wxFrame *frame)
974{
975 m_invokingWindow = frame;
976 wxMenuList::compatibility_iterator node = m_menus.GetFirst();
977 while (node)
978 {
979 wxMenu *menu = node->GetData();
980 wxMenubarSetInvokingWindow( menu, frame );
981 node = node->GetNext();
982 }
983}
984
985void wxMenuBar::Detach()
986{
987 wxMenuBarBase::Detach() ;
988}
989
990void wxMenuBar::Attach(wxFrame *frame)
991{
992 wxMenuBarBase::Attach( frame ) ;
993}
994// ---------------------------------------------------------------------------
995// wxMenuBar searching for menu items
996// ---------------------------------------------------------------------------
997
998// Find the itemString in menuString, and return the item id or wxNOT_FOUND
999int wxMenuBar::FindMenuItem(const wxString& menuString,
1000 const wxString& itemString) const
1001{
1002 wxString menuLabel = wxStripMenuCodes(menuString);
1003 size_t count = GetMenuCount();
1004 for ( size_t i = 0; i < count; i++ )
1005 {
1006 wxString title = wxStripMenuCodes(m_titles[i]);
1007 if ( menuLabel == title )
1008 return _wxMenuAt(m_menus, i)->FindItem(itemString);
1009 }
1010
1011 return wxNOT_FOUND;
1012}
1013
1014wxMenuItem *wxMenuBar::FindItem(int id, wxMenu **itemMenu) const
1015{
1016 if ( itemMenu )
1017 *itemMenu = NULL;
1018
1019 wxMenuItem *item = NULL;
1020 size_t count = GetMenuCount();
1021 for ( size_t i = 0; !item && (i < count); i++ )
1022 {
1023 item = _wxMenuAt(m_menus, i)->FindItem(id, itemMenu);
1024 }
1025
1026 return item;
1027}
1028
1029