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