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