]> git.saurik.com Git - wxWidgets.git/blob - src/mac/carbon/menu.cpp
wxMac Unicode support
[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 // wxWindows 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 = -2;
45 static MenuItemIndex firstUserHelpMenuItem = 0 ;
46
47 const short kwxMacMenuBarResource = 1 ;
48 const short kwxMacAppleMenuId = 1 ;
49
50 // ============================================================================
51 // implementation
52 // ============================================================================
53 static void wxMenubarUnsetInvokingWindow( wxMenu *menu ) ;
54 static void wxMenubarSetInvokingWindow( wxMenu *menu, wxWindow *win );
55
56 // Menus
57
58 // Construct a menu with optional title (then use append)
59
60 #ifdef __DARWIN__
61 short wxMenu::s_macNextMenuId = 3 ;
62 #else
63 short wxMenu::s_macNextMenuId = 2 ;
64 #endif
65
66 void wxMenu::Init()
67 {
68 m_doBreak = FALSE;
69 m_startRadioGroup = -1;
70
71 // create the menu
72 m_macMenuId = s_macNextMenuId++;
73 m_hMenu = UMANewMenu(m_macMenuId, m_title);
74
75 if ( !m_hMenu )
76 {
77 wxLogLastError("UMANewMenu failed");
78 }
79
80 // if we have a title, insert it in the beginning of the menu
81 if ( !!m_title )
82 {
83 Append(idMenuTitle, m_title) ;
84 AppendSeparator() ;
85 }
86 }
87
88 wxMenu::~wxMenu()
89 {
90 if (MAC_WXHMENU(m_hMenu))
91 ::DisposeMenu(MAC_WXHMENU(m_hMenu));
92 }
93
94 void wxMenu::Break()
95 {
96 // not available on the mac platform
97 }
98
99 void wxMenu::Attach(wxMenuBarBase *menubar)
100 {
101 wxMenuBase::Attach(menubar);
102
103 EndRadioGroup();
104 }
105
106 // function appends a new item or submenu to the menu
107 // append a new item or submenu to the menu
108 bool wxMenu::DoInsertOrAppend(wxMenuItem *pItem, size_t pos)
109 {
110 wxASSERT_MSG( pItem != NULL, wxT("can't append NULL item to the menu") );
111
112 if ( pItem->IsSeparator() )
113 {
114 if ( pos == (size_t)-1 )
115 MacAppendMenu(MAC_WXHMENU(m_hMenu), "\p-");
116 else
117 MacInsertMenuItem(MAC_WXHMENU(m_hMenu), "\p-" , pos);
118 }
119 else
120 {
121 wxMenu *pSubMenu = pItem->GetSubMenu() ;
122 if ( pSubMenu != NULL )
123 {
124 wxASSERT_MSG( pSubMenu->m_hMenu != NULL , wxT("invalid submenu added"));
125 pSubMenu->m_menuParent = this ;
126
127 if (wxMenuBar::MacGetInstalledMenuBar() == m_menuBar)
128 {
129 pSubMenu->MacBeforeDisplay( true ) ;
130 }
131
132 if ( pos == (size_t)-1 )
133 UMAAppendSubMenuItem(MAC_WXHMENU(m_hMenu), pItem->GetText(), pSubMenu->m_macMenuId);
134 else
135 UMAInsertSubMenuItem(MAC_WXHMENU(m_hMenu), pItem->GetText() , pos, pSubMenu->m_macMenuId);
136 pItem->UpdateItemBitmap() ;
137 pItem->UpdateItemStatus() ;
138 }
139 else
140 {
141 if ( pos == (size_t)-1 )
142 {
143 UMAAppendMenuItem(MAC_WXHMENU(m_hMenu), wxT("a") );
144 pos = CountMenuItems(MAC_WXHMENU(m_hMenu)) ;
145 }
146 else
147 {
148 UMAInsertMenuItem(MAC_WXHMENU(m_hMenu), wxT("a") , pos);
149 }
150
151 SetMenuItemCommandID( MAC_WXHMENU(m_hMenu) , pos , pItem->GetId() ) ;
152 pItem->UpdateItemText() ;
153 pItem->UpdateItemBitmap() ;
154 pItem->UpdateItemStatus() ;
155
156 if ( pItem->GetId() == idMenuTitle )
157 {
158 UMAEnableMenuItem(MAC_WXHMENU(m_hMenu) , pos , false ) ;
159 }
160 }
161 }
162 // if we're already attached to the menubar, we must update it
163 if ( IsAttached() )
164 {
165 m_menuBar->Refresh();
166 }
167 return TRUE ;
168 }
169
170 void wxMenu::EndRadioGroup()
171 {
172 // we're not inside a radio group any longer
173 m_startRadioGroup = -1;
174 }
175
176 bool wxMenu::DoAppend(wxMenuItem *item)
177 {
178 wxCHECK_MSG( item, FALSE, _T("NULL item in wxMenu::DoAppend") );
179
180 bool check = FALSE;
181
182 if ( item->GetKind() == wxITEM_RADIO )
183 {
184 int count = GetMenuItemCount();
185
186 if ( m_startRadioGroup == -1 )
187 {
188 // start a new radio group
189 m_startRadioGroup = count;
190
191 // for now it has just one element
192 item->SetAsRadioGroupStart();
193 item->SetRadioGroupEnd(m_startRadioGroup);
194
195 // ensure that we have a checked item in the radio group
196 check = TRUE;
197 }
198 else // extend the current radio group
199 {
200 // we need to update its end item
201 item->SetRadioGroupStart(m_startRadioGroup);
202 wxMenuItemList::Node *node = GetMenuItems().Item(m_startRadioGroup);
203
204 if ( node )
205 {
206 node->GetData()->SetRadioGroupEnd(count);
207 }
208 else
209 {
210 wxFAIL_MSG( _T("where is the radio group start item?") );
211 }
212 }
213 }
214 else // not a radio item
215 {
216 EndRadioGroup();
217 }
218
219 if ( !wxMenuBase::DoAppend(item) || !DoInsertOrAppend(item) )
220 {
221 return FALSE;
222 }
223
224 if ( check )
225 {
226 // check the item initially
227 item->Check(TRUE);
228 }
229
230 return TRUE;
231 }
232
233 bool wxMenu::DoInsert(size_t pos, wxMenuItem *item)
234 {
235 return wxMenuBase::DoInsert(pos, item) && DoInsertOrAppend(item, pos);
236 }
237
238 wxMenuItem *wxMenu::DoRemove(wxMenuItem *item)
239 {
240 // we need to find the items position in the child list
241 size_t pos;
242 wxMenuItemList::Node *node = GetMenuItems().GetFirst();
243 for ( pos = 0; node; pos++ )
244 {
245 if ( node->GetData() == item )
246 break;
247
248 node = node->GetNext();
249 }
250
251 // DoRemove() (unlike Remove) can only be called for existing item!
252 wxCHECK_MSG( node, NULL, wxT("bug in wxMenu::Remove logic") );
253
254 ::DeleteMenuItem(MAC_WXHMENU(m_hMenu) , pos + 1);
255
256 if ( IsAttached() )
257 {
258 // otherwise, the change won't be visible
259 m_menuBar->Refresh();
260 }
261
262 // and from internal data structures
263 return wxMenuBase::DoRemove(item);
264 }
265
266 void wxMenu::SetTitle(const wxString& label)
267 {
268 m_title = label ;
269 UMASetMenuTitle(MAC_WXHMENU(m_hMenu) , label ) ;
270 }
271 bool wxMenu::ProcessCommand(wxCommandEvent & event)
272 {
273 bool processed = FALSE;
274
275 #if WXWIN_COMPATIBILITY
276 // Try a callback
277 if (m_callback)
278 {
279 (void)(*(m_callback))(*this, event);
280 processed = TRUE;
281 }
282 #endif WXWIN_COMPATIBILITY
283
284 // Try the menu's event handler
285 if ( !processed && GetEventHandler())
286 {
287 processed = GetEventHandler()->ProcessEvent(event);
288 }
289
290 // Try the window the menu was popped up from (and up through the
291 // hierarchy)
292 wxWindow *win = GetInvokingWindow();
293 if ( !processed && win )
294 processed = win->GetEventHandler()->ProcessEvent(event);
295
296 return processed;
297 }
298
299
300 // ---------------------------------------------------------------------------
301 // other
302 // ---------------------------------------------------------------------------
303
304 wxWindow *wxMenu::GetWindow() const
305 {
306 if ( m_invokingWindow != NULL )
307 return m_invokingWindow;
308 else if ( m_menuBar != NULL)
309 return (wxWindow *) m_menuBar->GetFrame();
310
311 return NULL;
312 }
313
314 // helper functions returning the mac menu position for a certain item, note that this is
315 // mac-wise 1 - based, i.e. the first item has index 1 whereas on MSWin it has pos 0
316
317 int wxMenu::MacGetIndexFromId( int id )
318 {
319 size_t pos;
320 wxMenuItemList::Node *node = GetMenuItems().GetFirst();
321 for ( pos = 0; node; pos++ )
322 {
323 if ( node->GetData()->GetId() == id )
324 break;
325
326 node = node->GetNext();
327 }
328
329 if (!node)
330 return 0;
331
332 return pos + 1 ;
333 }
334
335 int wxMenu::MacGetIndexFromItem( wxMenuItem *pItem )
336 {
337 size_t pos;
338 wxMenuItemList::Node *node = GetMenuItems().GetFirst();
339 for ( pos = 0; node; pos++ )
340 {
341 if ( node->GetData() == pItem )
342 break;
343
344 node = node->GetNext();
345 }
346
347 if (!node)
348 return 0;
349
350 return pos + 1 ;
351 }
352
353 void wxMenu::MacEnableMenu( bool bDoEnable )
354 {
355 UMAEnableMenuItem(MAC_WXHMENU(m_hMenu) , 0 , bDoEnable ) ;
356
357 ::DrawMenuBar() ;
358 }
359
360 // MacOS needs to know about submenus somewhere within this menu
361 // before it can be displayed , also hide special menu items like preferences
362 // that are handled by the OS
363 void wxMenu::MacBeforeDisplay( bool isSubMenu )
364 {
365 wxMenuItem* previousItem = NULL ;
366 int pos ;
367 wxMenuItemList::Node *node;
368 wxMenuItem *item;
369 for (pos = 0, node = GetMenuItems().GetFirst(); node; node = node->GetNext(), pos++)
370 {
371 item = (wxMenuItem *)node->GetData();
372 wxMenu* subMenu = item->GetSubMenu() ;
373 if (subMenu)
374 {
375 subMenu->MacBeforeDisplay( true ) ;
376 }
377 else
378 {
379 #if TARGET_CARBON
380 if ( UMAGetSystemVersion() >= 0x1000 )
381 {
382 if ( item->GetId() == wxApp::s_macPreferencesMenuItemId || item->GetId() == wxApp::s_macExitMenuItemId)
383 {
384 ChangeMenuItemAttributes( MAC_WXHMENU( GetHMenu() ) , pos + 1, kMenuItemAttrHidden, 0 );
385 if ( GetMenuItems().GetCount() == pos + 1 && previousItem != NULL && previousItem->IsSeparator() )
386 {
387 ChangeMenuItemAttributes( MAC_WXHMENU( GetHMenu() ) , pos , kMenuItemAttrHidden, 0 );
388 }
389 }
390 }
391 #endif
392 }
393 previousItem = item ;
394 }
395
396 if ( isSubMenu )
397 ::InsertMenu(MAC_WXHMENU( GetHMenu()), -1);
398
399 }
400 // undo all changes from the MacBeforeDisplay call
401 void wxMenu::MacAfterDisplay( bool isSubMenu )
402 {
403 if ( isSubMenu )
404 ::DeleteMenu(MacGetMenuId());
405
406 wxMenuItem* previousItem = NULL ;
407 int pos ;
408 wxMenuItemList::Node *node;
409 wxMenuItem *item;
410 for (pos = 0, node = GetMenuItems().GetFirst(); node; node = node->GetNext(), pos++)
411 {
412 item = (wxMenuItem *)node->GetData();
413 wxMenu* subMenu = item->GetSubMenu() ;
414 if (subMenu)
415 {
416 subMenu->MacAfterDisplay( true ) ;
417 }
418 else
419 {
420 // no need to undo hidings
421 }
422 previousItem = item ;
423 }
424 }
425
426 // Menu Bar
427
428 /*
429
430 Mac Implementation note :
431
432 The Mac has only one global menubar, so we attempt to install the currently
433 active menubar from a frame, we currently don't take into account mdi-frames
434 which would ask for menu-merging
435
436 Secondly there is no mac api for changing a menubar that is not the current
437 menubar, so we have to wait for preparing the actual menubar until the
438 wxMenubar is to be used
439
440 We can in subsequent versions use MacInstallMenuBar to provide some sort of
441 auto-merge for MDI in case this will be necessary
442
443 */
444
445 wxMenuBar* wxMenuBar::s_macInstalledMenuBar = NULL ;
446
447 void wxMenuBar::Init()
448 {
449 m_eventHandler = this;
450 m_menuBarFrame = NULL;
451 m_invokingWindow = (wxWindow*) NULL;
452 }
453
454 wxMenuBar::wxMenuBar()
455 {
456 Init();
457 }
458
459 wxMenuBar::wxMenuBar( long WXUNUSED(style) )
460 {
461 Init();
462 }
463
464
465 wxMenuBar::wxMenuBar(int count, wxMenu *menus[], const wxString titles[])
466 {
467 Init();
468
469 m_titles.Alloc(count);
470
471 for ( int i = 0; i < count; i++ )
472 {
473 m_menus.Append(menus[i]);
474 m_titles.Add(titles[i]);
475
476 menus[i]->Attach(this);
477 }
478 }
479
480 wxMenuBar::~wxMenuBar()
481 {
482 if (s_macInstalledMenuBar == this)
483 {
484 ::ClearMenuBar();
485 s_macInstalledMenuBar = NULL;
486 }
487
488 }
489
490 void wxMenuBar::Refresh(bool WXUNUSED(eraseBackground), const wxRect *WXUNUSED(rect))
491 {
492 wxCHECK_RET( IsAttached(), wxT("can't refresh unatteched menubar") );
493
494 DrawMenuBar();
495 }
496
497 void wxMenuBar::MacInstallMenuBar()
498 {
499 if ( s_macInstalledMenuBar == this )
500 return ;
501
502 wxStAppResource resload ;
503
504 Handle menubar = ::GetNewMBar( kwxMacMenuBarResource ) ;
505 wxString message ;
506 wxCHECK_RET( menubar != NULL, wxT("can't read MBAR resource") );
507 ::SetMenuBar( menubar ) ;
508 #if TARGET_API_MAC_CARBON
509 ::DisposeMenuBar( menubar ) ;
510 #else
511 ::DisposeHandle( menubar ) ;
512 #endif
513
514 #if TARGET_API_MAC_OS8
515 MenuHandle menu = ::GetMenuHandle( kwxMacAppleMenuId ) ;
516 if ( CountMenuItems( menu ) == 2 )
517 {
518 ::AppendResMenu(menu, 'DRVR');
519 }
520 #endif
521
522 // clean-up the help menu before adding new items
523 MenuHandle mh = NULL ;
524 if ( UMAGetHelpMenu( &mh , &firstUserHelpMenuItem) == noErr )
525 {
526 for ( int i = CountMenuItems( mh ) ; i >= firstUserHelpMenuItem ; --i )
527 {
528 DeleteMenuItem( mh , i ) ;
529 }
530 }
531 else
532 {
533 mh = NULL ;
534 }
535 #if TARGET_CARBON
536 if ( UMAGetSystemVersion() >= 0x1000 && wxApp::s_macPreferencesMenuItemId)
537 {
538 wxMenuItem *item = FindItem( wxApp::s_macPreferencesMenuItemId , NULL ) ;
539 if ( item == NULL || !(item->IsEnabled()) )
540 DisableMenuCommand( NULL , kHICommandPreferences ) ;
541 else
542 EnableMenuCommand( NULL , kHICommandPreferences ) ;
543 }
544 #endif
545 for (size_t i = 0; i < m_menus.GetCount(); i++)
546 {
547 Str255 label;
548 wxMenuItemList::Node *node;
549 wxMenuItem *item;
550 int pos ;
551 wxMenu* menu = m_menus[i] , *subMenu = NULL ;
552
553 if( m_titles[i] == wxT("?") || m_titles[i] == wxT("&?") || m_titles[i] == wxApp::s_macHelpMenuTitleName )
554 {
555 if ( mh == NULL )
556 {
557 continue ;
558 }
559
560 for (pos = 0 , node = menu->GetMenuItems().GetFirst(); node; node = node->GetNext(), pos++)
561 {
562 item = (wxMenuItem *)node->GetData();
563 subMenu = item->GetSubMenu() ;
564 if (subMenu)
565 {
566 // we don't support hierarchical menus in the help menu yet
567 }
568 else
569 {
570 if ( item->IsSeparator() )
571 {
572 if ( mh )
573 MacAppendMenu(mh, "\p-" );
574 }
575 else
576 {
577 wxAcceleratorEntry* entry = wxGetAccelFromString( item->GetText() ) ;
578
579 if ( item->GetId() == wxApp::s_macAboutMenuItemId )
580 {
581 UMASetMenuItemText( GetMenuHandle( kwxMacAppleMenuId ) , 1 , item->GetText() );
582 UMAEnableMenuItem( GetMenuHandle( kwxMacAppleMenuId ) , 1 , true );
583 SetMenuItemCommandID( GetMenuHandle( kwxMacAppleMenuId ) , 1 , item->GetId() ) ;
584 UMASetMenuItemShortcut( GetMenuHandle( kwxMacAppleMenuId ) , 1 , entry ) ;
585 }
586 else
587 {
588 if ( mh )
589 {
590 UMAAppendMenuItem(mh, item->GetText() , entry );
591 SetMenuItemCommandID( mh , CountMenuItems(mh) , item->GetId() ) ;
592 }
593 }
594
595 delete entry ;
596 }
597 }
598 }
599 }
600 else
601 {
602 UMASetMenuTitle( MAC_WXHMENU(menu->GetHMenu()) , m_titles[i] ) ;
603 m_menus[i]->MacBeforeDisplay(false) ;
604 ::InsertMenu(MAC_WXHMENU(m_menus[i]->GetHMenu()), 0);
605 }
606 }
607 ::DrawMenuBar() ;
608 s_macInstalledMenuBar = this;
609 }
610
611 void wxMenuBar::EnableTop(size_t pos, bool enable)
612 {
613 wxCHECK_RET( IsAttached(), wxT("doesn't work with unattached menubars") );
614 m_menus[pos]->MacEnableMenu( enable ) ;
615 Refresh();
616 }
617
618 void wxMenuBar::SetLabelTop(size_t pos, const wxString& label)
619 {
620 wxCHECK_RET( pos < GetMenuCount(), wxT("invalid menu index") );
621
622 m_titles[pos] = label;
623
624 if ( !IsAttached() )
625 {
626 return;
627 }
628
629 m_menus[pos]->SetTitle( label ) ;
630 if (wxMenuBar::s_macInstalledMenuBar == this) // are we currently installed ?
631 {
632 ::SetMenuBar( GetMenuBar() ) ;
633 ::InvalMenuBar() ;
634 }
635 }
636
637 wxString wxMenuBar::GetLabelTop(size_t pos) const
638 {
639 wxCHECK_MSG( pos < GetMenuCount(), wxEmptyString,
640 wxT("invalid menu index in wxMenuBar::GetLabelTop") );
641
642 return m_titles[pos];
643 }
644
645 int wxMenuBar::FindMenu(const wxString& title)
646 {
647 wxString menuTitle = wxStripMenuCodes(title);
648
649 size_t count = GetMenuCount();
650 for ( size_t i = 0; i < count; i++ )
651 {
652 wxString title = wxStripMenuCodes(m_titles[i]);
653 if ( menuTitle == title )
654 return i;
655 }
656
657 return wxNOT_FOUND;
658
659 }
660
661
662 // ---------------------------------------------------------------------------
663 // wxMenuBar construction
664 // ---------------------------------------------------------------------------
665
666 // ---------------------------------------------------------------------------
667 // wxMenuBar construction
668 // ---------------------------------------------------------------------------
669
670 wxMenu *wxMenuBar::Replace(size_t pos, wxMenu *menu, const wxString& title)
671 {
672 wxMenu *menuOld = wxMenuBarBase::Replace(pos, menu, title);
673 if ( !menuOld )
674 return FALSE;
675 m_titles[pos] = title;
676
677 if ( IsAttached() )
678 {
679 if (s_macInstalledMenuBar == this)
680 {
681 menuOld->MacAfterDisplay( false ) ;
682 ::DeleteMenu( menuOld->MacGetMenuId() /* m_menus[pos]->MacGetMenuId() */ ) ;
683 {
684 menu->MacBeforeDisplay( false ) ;
685 UMASetMenuTitle( MAC_WXHMENU(menu->GetHMenu()) , title ) ;
686 if ( pos == m_menus.GetCount() - 1)
687 {
688 ::InsertMenu( MAC_WXHMENU(menu->GetHMenu()) , 0 ) ;
689 }
690 else
691 {
692 ::InsertMenu( MAC_WXHMENU(menu->GetHMenu()) , m_menus[pos+1]->MacGetMenuId() ) ;
693 }
694 }
695 }
696
697 Refresh();
698 }
699
700 return menuOld;
701 }
702
703 bool wxMenuBar::Insert(size_t pos, wxMenu *menu, const wxString& title)
704 {
705 if ( !wxMenuBarBase::Insert(pos, menu, title) )
706 return FALSE;
707
708 m_titles.Insert(title, pos);
709
710 UMASetMenuTitle( MAC_WXHMENU(menu->GetHMenu()) , title ) ;
711
712 if ( IsAttached() && s_macInstalledMenuBar == this )
713 {
714 if (s_macInstalledMenuBar == this)
715 {
716 menu->MacBeforeDisplay( false ) ;
717 if ( pos == (size_t) -1 || pos + 1 == m_menus.GetCount() )
718 {
719 ::InsertMenu( MAC_WXHMENU(menu->GetHMenu()) , 0 ) ;
720 }
721 else
722 {
723 ::InsertMenu( MAC_WXHMENU(menu->GetHMenu()) , m_menus[pos+1]->MacGetMenuId() ) ;
724 }
725 }
726 Refresh();
727 }
728
729 return TRUE;
730 }
731
732 wxMenu *wxMenuBar::Remove(size_t pos)
733 {
734 wxMenu *menu = wxMenuBarBase::Remove(pos);
735 if ( !menu )
736 return NULL;
737
738 if ( IsAttached() )
739 {
740 if (s_macInstalledMenuBar == this)
741 {
742 ::DeleteMenu( menu->MacGetMenuId() /* m_menus[pos]->MacGetMenuId() */ ) ;
743 }
744
745 menu->Detach();
746
747 Refresh();
748 }
749
750 m_titles.Remove(pos);
751
752 return menu;
753 }
754
755 bool wxMenuBar::Append(wxMenu *menu, const wxString& title)
756 {
757 WXHMENU submenu = menu ? menu->GetHMenu() : 0;
758 wxCHECK_MSG( submenu, FALSE, wxT("can't append invalid menu to menubar") );
759
760 if ( !wxMenuBarBase::Append(menu, title) )
761 return FALSE;
762
763 m_titles.Add(title);
764
765 UMASetMenuTitle( MAC_WXHMENU(menu->GetHMenu()) , title ) ;
766
767 if ( IsAttached() )
768 {
769 if (s_macInstalledMenuBar == this)
770 {
771 ::InsertMenu( MAC_WXHMENU(menu->GetHMenu()) , 0 ) ;
772 }
773
774 Refresh();
775 }
776
777 // m_invokingWindow is set after wxFrame::SetMenuBar(). This call enables
778 // adding menu later on.
779 if (m_invokingWindow)
780 wxMenubarSetInvokingWindow( menu, m_invokingWindow );
781
782 return TRUE;
783 }
784
785 static void wxMenubarUnsetInvokingWindow( wxMenu *menu )
786 {
787 menu->SetInvokingWindow( (wxWindow*) NULL );
788
789 wxMenuItemList::Node *node = menu->GetMenuItems().GetFirst();
790 while (node)
791 {
792 wxMenuItem *menuitem = node->GetData();
793 if (menuitem->IsSubMenu())
794 wxMenubarUnsetInvokingWindow( menuitem->GetSubMenu() );
795 node = node->GetNext();
796 }
797 }
798
799 static void wxMenubarSetInvokingWindow( wxMenu *menu, wxWindow *win )
800 {
801 menu->SetInvokingWindow( win );
802
803 wxMenuItemList::Node *node = menu->GetMenuItems().GetFirst();
804 while (node)
805 {
806 wxMenuItem *menuitem = node->GetData();
807 if (menuitem->IsSubMenu())
808 wxMenubarSetInvokingWindow( menuitem->GetSubMenu() , win );
809 node = node->GetNext();
810 }
811 }
812
813 void wxMenuBar::UnsetInvokingWindow()
814 {
815 m_invokingWindow = (wxWindow*) NULL;
816 wxMenuList::Node *node = m_menus.GetFirst();
817 while (node)
818 {
819 wxMenu *menu = node->GetData();
820 wxMenubarUnsetInvokingWindow( menu );
821 node = node->GetNext();
822 }
823 }
824
825 void wxMenuBar::SetInvokingWindow(wxFrame *frame)
826 {
827 m_invokingWindow = frame;
828 wxMenuList::Node *node = m_menus.GetFirst();
829 while (node)
830 {
831 wxMenu *menu = node->GetData();
832 wxMenubarSetInvokingWindow( menu, frame );
833 node = node->GetNext();
834 }
835 }
836
837 void wxMenuBar::Detach()
838 {
839 wxMenuBarBase::Detach() ;
840 }
841
842 void wxMenuBar::Attach(wxFrame *frame)
843 {
844 wxMenuBarBase::Attach( frame ) ;
845 }
846 // ---------------------------------------------------------------------------
847 // wxMenuBar searching for menu items
848 // ---------------------------------------------------------------------------
849
850 // Find the itemString in menuString, and return the item id or wxNOT_FOUND
851 int wxMenuBar::FindMenuItem(const wxString& menuString,
852 const wxString& itemString) const
853 {
854 wxString menuLabel = wxStripMenuCodes(menuString);
855 size_t count = GetMenuCount();
856 for ( size_t i = 0; i < count; i++ )
857 {
858 wxString title = wxStripMenuCodes(m_titles[i]);
859 if ( menuString == title )
860 return m_menus[i]->FindItem(itemString);
861 }
862
863 return wxNOT_FOUND;
864 }
865
866 wxMenuItem *wxMenuBar::FindItem(int id, wxMenu **itemMenu) const
867 {
868 if ( itemMenu )
869 *itemMenu = NULL;
870
871 wxMenuItem *item = NULL;
872 size_t count = GetMenuCount();
873 for ( size_t i = 0; !item && (i < count); i++ )
874 {
875 item = m_menus[i]->FindItem(id, itemMenu);
876 }
877
878 return item;
879 }
880
881