]> git.saurik.com Git - wxWidgets.git/blob - src/mac/menu.cpp
Applied pop menu patch.
[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("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 #if WXWIN_COMPATIBILITY
280 // Try a callback
281 if (m_callback)
282 {
283 (void)(*(m_callback))(*this, event);
284 processed = TRUE;
285 }
286 #endif WXWIN_COMPATIBILITY
287
288 // Try the menu's event handler
289 if ( !processed && GetEventHandler())
290 {
291 processed = GetEventHandler()->ProcessEvent(event);
292 }
293
294 // Try the window the menu was popped up from (and up through the
295 // hierarchy)
296 wxWindow *win = GetInvokingWindow();
297 if ( !processed && win )
298 processed = win->GetEventHandler()->ProcessEvent(event);
299
300 return processed;
301 }
302
303
304 // ---------------------------------------------------------------------------
305 // other
306 // ---------------------------------------------------------------------------
307
308 wxWindow *wxMenu::GetWindow() const
309 {
310 if ( m_invokingWindow != NULL )
311 return m_invokingWindow;
312 else if ( m_menuBar != NULL)
313 return (wxWindow *) m_menuBar->GetFrame();
314
315 return NULL;
316 }
317
318 // helper functions returning the mac menu position for a certain item, note that this is
319 // mac-wise 1 - based, i.e. the first item has index 1 whereas on MSWin it has pos 0
320
321 int wxMenu::MacGetIndexFromId( int id )
322 {
323 size_t pos;
324 wxMenuItemList::Node *node = GetMenuItems().GetFirst();
325 for ( pos = 0; node; pos++ )
326 {
327 if ( node->GetData()->GetId() == id )
328 break;
329
330 node = node->GetNext();
331 }
332
333 if (!node)
334 return 0;
335
336 return pos + 1 ;
337 }
338
339 int wxMenu::MacGetIndexFromItem( wxMenuItem *pItem )
340 {
341 size_t pos;
342 wxMenuItemList::Node *node = GetMenuItems().GetFirst();
343 for ( pos = 0; node; pos++ )
344 {
345 if ( node->GetData() == pItem )
346 break;
347
348 node = node->GetNext();
349 }
350
351 if (!node)
352 return 0;
353
354 return pos + 1 ;
355 }
356
357 void wxMenu::MacEnableMenu( bool bDoEnable )
358 {
359 UMAEnableMenuItem(MAC_WXHMENU(m_hMenu) , 0 , bDoEnable ) ;
360
361 ::DrawMenuBar() ;
362 }
363
364 // MacOS needs to know about submenus somewhere within this menu
365 // before it can be displayed , also hide special menu items like preferences
366 // that are handled by the OS
367 void wxMenu::MacBeforeDisplay( bool isSubMenu )
368 {
369 wxMenuItem* previousItem = NULL ;
370 size_t pos ;
371 wxMenuItemList::Node *node;
372 wxMenuItem *item;
373 for (pos = 0, node = GetMenuItems().GetFirst(); node; node = node->GetNext(), pos++)
374 {
375 item = (wxMenuItem *)node->GetData();
376 wxMenu* subMenu = item->GetSubMenu() ;
377 if (subMenu)
378 {
379 subMenu->MacBeforeDisplay( true ) ;
380 }
381 else
382 {
383 #if TARGET_CARBON
384 if ( UMAGetSystemVersion() >= 0x1000 )
385 {
386 if ( item->GetId() == wxApp::s_macPreferencesMenuItemId || item->GetId() == wxApp::s_macExitMenuItemId)
387 {
388 ChangeMenuItemAttributes( MAC_WXHMENU( GetHMenu() ) , pos + 1, kMenuItemAttrHidden, 0 );
389 if ( GetMenuItems().GetCount() == pos + 1 &&
390 previousItem != NULL &&
391 previousItem->IsSeparator() )
392 {
393 ChangeMenuItemAttributes( MAC_WXHMENU( GetHMenu() ) , pos , kMenuItemAttrHidden, 0 );
394 }
395 }
396 }
397 #endif
398 }
399 previousItem = item ;
400 }
401
402 if ( isSubMenu )
403 ::InsertMenu(MAC_WXHMENU( GetHMenu()), -1);
404
405 }
406 // undo all changes from the MacBeforeDisplay call
407 void wxMenu::MacAfterDisplay( bool isSubMenu )
408 {
409 if ( isSubMenu )
410 ::DeleteMenu(MacGetMenuId());
411
412 wxMenuItem* previousItem = NULL ;
413 int pos ;
414 wxMenuItemList::Node *node;
415 wxMenuItem *item;
416 for (pos = 0, node = GetMenuItems().GetFirst(); node; node = node->GetNext(), pos++)
417 {
418 item = (wxMenuItem *)node->GetData();
419 wxMenu* subMenu = item->GetSubMenu() ;
420 if (subMenu)
421 {
422 subMenu->MacAfterDisplay( true ) ;
423 }
424 else
425 {
426 // no need to undo hidings
427 }
428 previousItem = item ;
429 }
430 }
431
432 // Menu Bar
433
434 /*
435
436 Mac Implementation note :
437
438 The Mac has only one global menubar, so we attempt to install the currently
439 active menubar from a frame, we currently don't take into account mdi-frames
440 which would ask for menu-merging
441
442 Secondly there is no mac api for changing a menubar that is not the current
443 menubar, so we have to wait for preparing the actual menubar until the
444 wxMenubar is to be used
445
446 We can in subsequent versions use MacInstallMenuBar to provide some sort of
447 auto-merge for MDI in case this will be necessary
448
449 */
450
451 wxMenuBar* wxMenuBar::s_macInstalledMenuBar = NULL ;
452 wxMenuBar* wxMenuBar::s_macCommonMenuBar = NULL ;
453
454 void wxMenuBar::Init()
455 {
456 m_eventHandler = this;
457 m_menuBarFrame = NULL;
458 m_invokingWindow = (wxWindow*) NULL;
459 }
460
461 wxMenuBar::wxMenuBar()
462 {
463 Init();
464 }
465
466 wxMenuBar::wxMenuBar( long WXUNUSED(style) )
467 {
468 Init();
469 }
470
471
472 wxMenuBar::wxMenuBar(int count, wxMenu *menus[], const wxString titles[])
473 {
474 Init();
475
476 m_titles.Alloc(count);
477
478 for ( int i = 0; i < count; i++ )
479 {
480 m_menus.Append(menus[i]);
481 m_titles.Add(titles[i]);
482
483 menus[i]->Attach(this);
484 }
485 }
486
487 wxMenuBar::~wxMenuBar()
488 {
489 if (s_macCommonMenuBar == this)
490 s_macCommonMenuBar = NULL;
491 if (s_macInstalledMenuBar == this)
492 {
493 ::ClearMenuBar();
494 s_macInstalledMenuBar = NULL;
495 }
496
497 }
498
499 void wxMenuBar::Refresh(bool WXUNUSED(eraseBackground), const wxRect *WXUNUSED(rect))
500 {
501 wxCHECK_RET( IsAttached(), wxT("can't refresh unatteched menubar") );
502
503 DrawMenuBar();
504 }
505
506 void wxMenuBar::MacInstallMenuBar()
507 {
508 if ( s_macInstalledMenuBar == this )
509 return ;
510
511 wxStAppResource resload ;
512
513 Handle menubar = ::GetNewMBar( kwxMacMenuBarResource ) ;
514 wxString message ;
515 wxCHECK_RET( menubar != NULL, wxT("can't read MBAR resource") );
516 ::SetMenuBar( menubar ) ;
517 #if TARGET_API_MAC_CARBON
518 ::DisposeMenuBar( menubar ) ;
519 #else
520 ::DisposeHandle( menubar ) ;
521 #endif
522
523 #if TARGET_API_MAC_OS8
524 MenuHandle menu = ::GetMenuHandle( kwxMacAppleMenuId ) ;
525 if ( CountMenuItems( menu ) == 2 )
526 {
527 ::AppendResMenu(menu, 'DRVR');
528 }
529 #endif
530
531 // clean-up the help menu before adding new items
532 MenuHandle mh = NULL ;
533 if ( UMAGetHelpMenu( &mh , &firstUserHelpMenuItem) == noErr )
534 {
535 for ( int i = CountMenuItems( mh ) ; i >= firstUserHelpMenuItem ; --i )
536 {
537 DeleteMenuItem( mh , i ) ;
538 }
539 }
540 else
541 {
542 mh = NULL ;
543 }
544 #if TARGET_CARBON
545 if ( UMAGetSystemVersion() >= 0x1000 && wxApp::s_macPreferencesMenuItemId)
546 {
547 wxMenuItem *item = FindItem( wxApp::s_macPreferencesMenuItemId , NULL ) ;
548 if ( item == NULL || !(item->IsEnabled()) )
549 DisableMenuCommand( NULL , kHICommandPreferences ) ;
550 else
551 EnableMenuCommand( NULL , kHICommandPreferences ) ;
552 }
553 #endif
554 for (size_t i = 0; i < m_menus.GetCount(); i++)
555 {
556 wxMenuItemList::Node *node;
557 wxMenuItem *item;
558 int pos ;
559 wxMenu* menu = m_menus[i] , *subMenu = NULL ;
560
561 if( m_titles[i] == wxT("?") || m_titles[i] == wxT("&?") || m_titles[i] == wxApp::s_macHelpMenuTitleName )
562 {
563 if ( mh == NULL )
564 {
565 continue ;
566 }
567
568 for (pos = 0 , node = menu->GetMenuItems().GetFirst(); node; node = node->GetNext(), pos++)
569 {
570 item = (wxMenuItem *)node->GetData();
571 subMenu = item->GetSubMenu() ;
572 if (subMenu)
573 {
574 // we don't support hierarchical menus in the help menu yet
575 }
576 else
577 {
578 if ( item->IsSeparator() )
579 {
580 if ( mh )
581 MacAppendMenu(mh, "\p-" );
582 }
583 else
584 {
585 wxAcceleratorEntry* entry = wxGetAccelFromString( item->GetText() ) ;
586
587 if ( item->GetId() == wxApp::s_macAboutMenuItemId )
588 {
589 UMASetMenuItemText( GetMenuHandle( kwxMacAppleMenuId ) , 1 , item->GetText() );
590 UMAEnableMenuItem( GetMenuHandle( kwxMacAppleMenuId ) , 1 , true );
591 SetMenuItemCommandID( GetMenuHandle( kwxMacAppleMenuId ) , 1 , item->GetId() ) ;
592 UMASetMenuItemShortcut( GetMenuHandle( kwxMacAppleMenuId ) , 1 , entry ) ;
593 }
594 else
595 {
596 if ( mh )
597 {
598 UMAAppendMenuItem(mh, item->GetText() , entry );
599 SetMenuItemCommandID( mh , CountMenuItems(mh) , item->GetId() ) ;
600 }
601 }
602
603 delete entry ;
604 }
605 }
606 }
607 }
608 else
609 {
610 UMASetMenuTitle( MAC_WXHMENU(menu->GetHMenu()) , m_titles[i] ) ;
611 m_menus[i]->MacBeforeDisplay(false) ;
612 ::InsertMenu(MAC_WXHMENU(m_menus[i]->GetHMenu()), 0);
613 }
614 }
615 ::DrawMenuBar() ;
616 s_macInstalledMenuBar = this;
617 }
618
619 void wxMenuBar::EnableTop(size_t pos, bool enable)
620 {
621 wxCHECK_RET( IsAttached(), wxT("doesn't work with unattached menubars") );
622 m_menus[pos]->MacEnableMenu( enable ) ;
623 Refresh();
624 }
625
626 void wxMenuBar::SetLabelTop(size_t pos, const wxString& label)
627 {
628 wxCHECK_RET( pos < GetMenuCount(), wxT("invalid menu index") );
629
630 m_titles[pos] = label;
631
632 if ( !IsAttached() )
633 {
634 return;
635 }
636
637 m_menus[pos]->SetTitle( label ) ;
638 if (wxMenuBar::s_macInstalledMenuBar == this) // are we currently installed ?
639 {
640 ::SetMenuBar( GetMenuBar() ) ;
641 ::InvalMenuBar() ;
642 }
643 }
644
645 wxString wxMenuBar::GetLabelTop(size_t pos) const
646 {
647 wxCHECK_MSG( pos < GetMenuCount(), wxEmptyString,
648 wxT("invalid menu index in wxMenuBar::GetLabelTop") );
649
650 return m_titles[pos];
651 }
652
653 int wxMenuBar::FindMenu(const wxString& title)
654 {
655 wxString menuTitle = wxStripMenuCodes(title);
656
657 size_t count = GetMenuCount();
658 for ( size_t i = 0; i < count; i++ )
659 {
660 wxString title = wxStripMenuCodes(m_titles[i]);
661 if ( menuTitle == title )
662 return i;
663 }
664
665 return wxNOT_FOUND;
666
667 }
668
669
670 // ---------------------------------------------------------------------------
671 // wxMenuBar construction
672 // ---------------------------------------------------------------------------
673
674 // ---------------------------------------------------------------------------
675 // wxMenuBar construction
676 // ---------------------------------------------------------------------------
677
678 wxMenu *wxMenuBar::Replace(size_t pos, wxMenu *menu, const wxString& title)
679 {
680 wxMenu *menuOld = wxMenuBarBase::Replace(pos, menu, title);
681 if ( !menuOld )
682 return FALSE;
683 m_titles[pos] = title;
684
685 if ( IsAttached() )
686 {
687 if (s_macInstalledMenuBar == this)
688 {
689 menuOld->MacAfterDisplay( false ) ;
690 ::DeleteMenu( menuOld->MacGetMenuId() /* m_menus[pos]->MacGetMenuId() */ ) ;
691 {
692 menu->MacBeforeDisplay( false ) ;
693 UMASetMenuTitle( MAC_WXHMENU(menu->GetHMenu()) , title ) ;
694 if ( pos == m_menus.GetCount() - 1)
695 {
696 ::InsertMenu( MAC_WXHMENU(menu->GetHMenu()) , 0 ) ;
697 }
698 else
699 {
700 ::InsertMenu( MAC_WXHMENU(menu->GetHMenu()) , m_menus[pos+1]->MacGetMenuId() ) ;
701 }
702 }
703 }
704
705 Refresh();
706 }
707
708 return menuOld;
709 }
710
711 bool wxMenuBar::Insert(size_t pos, wxMenu *menu, const wxString& title)
712 {
713 if ( !wxMenuBarBase::Insert(pos, menu, title) )
714 return FALSE;
715
716 m_titles.Insert(title, pos);
717
718 UMASetMenuTitle( MAC_WXHMENU(menu->GetHMenu()) , title ) ;
719
720 if ( IsAttached() && s_macInstalledMenuBar == this )
721 {
722 if (s_macInstalledMenuBar == this)
723 {
724 menu->MacBeforeDisplay( false ) ;
725 if ( pos == (size_t) -1 || pos + 1 == m_menus.GetCount() )
726 {
727 ::InsertMenu( MAC_WXHMENU(menu->GetHMenu()) , 0 ) ;
728 }
729 else
730 {
731 ::InsertMenu( MAC_WXHMENU(menu->GetHMenu()) , m_menus[pos+1]->MacGetMenuId() ) ;
732 }
733 }
734 Refresh();
735 }
736
737 return TRUE;
738 }
739
740 wxMenu *wxMenuBar::Remove(size_t pos)
741 {
742 wxMenu *menu = wxMenuBarBase::Remove(pos);
743 if ( !menu )
744 return NULL;
745
746 if ( IsAttached() )
747 {
748 if (s_macInstalledMenuBar == this)
749 {
750 ::DeleteMenu( menu->MacGetMenuId() /* m_menus[pos]->MacGetMenuId() */ ) ;
751 }
752
753 menu->Detach();
754
755 Refresh();
756 }
757
758 m_titles.RemoveAt(pos);
759
760 return menu;
761 }
762
763 bool wxMenuBar::Append(wxMenu *menu, const wxString& title)
764 {
765 WXHMENU submenu = menu ? menu->GetHMenu() : 0;
766 wxCHECK_MSG( submenu, FALSE, wxT("can't append invalid menu to menubar") );
767
768 if ( !wxMenuBarBase::Append(menu, title) )
769 return FALSE;
770
771 m_titles.Add(title);
772
773 UMASetMenuTitle( MAC_WXHMENU(menu->GetHMenu()) , title ) ;
774
775 if ( IsAttached() )
776 {
777 if (s_macInstalledMenuBar == this)
778 {
779 ::InsertMenu( MAC_WXHMENU(menu->GetHMenu()) , 0 ) ;
780 }
781
782 Refresh();
783 }
784
785 // m_invokingWindow is set after wxFrame::SetMenuBar(). This call enables
786 // adding menu later on.
787 if (m_invokingWindow)
788 wxMenubarSetInvokingWindow( menu, m_invokingWindow );
789
790 return TRUE;
791 }
792
793 static void wxMenubarUnsetInvokingWindow( wxMenu *menu )
794 {
795 menu->SetInvokingWindow( (wxWindow*) NULL );
796
797 wxMenuItemList::Node *node = menu->GetMenuItems().GetFirst();
798 while (node)
799 {
800 wxMenuItem *menuitem = node->GetData();
801 if (menuitem->IsSubMenu())
802 wxMenubarUnsetInvokingWindow( menuitem->GetSubMenu() );
803 node = node->GetNext();
804 }
805 }
806
807 static void wxMenubarSetInvokingWindow( wxMenu *menu, wxWindow *win )
808 {
809 menu->SetInvokingWindow( win );
810
811 wxMenuItemList::Node *node = menu->GetMenuItems().GetFirst();
812 while (node)
813 {
814 wxMenuItem *menuitem = node->GetData();
815 if (menuitem->IsSubMenu())
816 wxMenubarSetInvokingWindow( menuitem->GetSubMenu() , win );
817 node = node->GetNext();
818 }
819 }
820
821 void wxMenuBar::UnsetInvokingWindow()
822 {
823 m_invokingWindow = (wxWindow*) NULL;
824 wxMenuList::Node *node = m_menus.GetFirst();
825 while (node)
826 {
827 wxMenu *menu = node->GetData();
828 wxMenubarUnsetInvokingWindow( menu );
829 node = node->GetNext();
830 }
831 }
832
833 void wxMenuBar::SetInvokingWindow(wxFrame *frame)
834 {
835 m_invokingWindow = frame;
836 wxMenuList::Node *node = m_menus.GetFirst();
837 while (node)
838 {
839 wxMenu *menu = node->GetData();
840 wxMenubarSetInvokingWindow( menu, frame );
841 node = node->GetNext();
842 }
843 }
844
845 void wxMenuBar::Detach()
846 {
847 wxMenuBarBase::Detach() ;
848 }
849
850 void wxMenuBar::Attach(wxFrame *frame)
851 {
852 wxMenuBarBase::Attach( frame ) ;
853 }
854 // ---------------------------------------------------------------------------
855 // wxMenuBar searching for menu items
856 // ---------------------------------------------------------------------------
857
858 // Find the itemString in menuString, and return the item id or wxNOT_FOUND
859 int wxMenuBar::FindMenuItem(const wxString& menuString,
860 const wxString& itemString) const
861 {
862 wxString menuLabel = wxStripMenuCodes(menuString);
863 size_t count = GetMenuCount();
864 for ( size_t i = 0; i < count; i++ )
865 {
866 wxString title = wxStripMenuCodes(m_titles[i]);
867 if ( menuString == title )
868 return m_menus[i]->FindItem(itemString);
869 }
870
871 return wxNOT_FOUND;
872 }
873
874 wxMenuItem *wxMenuBar::FindItem(int id, wxMenu **itemMenu) const
875 {
876 if ( itemMenu )
877 *itemMenu = NULL;
878
879 wxMenuItem *item = NULL;
880 size_t count = GetMenuCount();
881 for ( size_t i = 0; !item && (i < count); i++ )
882 {
883 item = m_menus[i]->FindItem(id, itemMenu);
884 }
885
886 return item;
887 }
888
889