]> git.saurik.com Git - wxWidgets.git/blob - src/mac/carbon/menu.cpp
added 3-state checkboxes (patch 813790)
[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(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 menu->Detach();
745
746 Refresh();
747 }
748
749 m_titles.RemoveAt(pos);
750
751 return menu;
752 }
753
754 bool wxMenuBar::Append(wxMenu *menu, const wxString& title)
755 {
756 WXHMENU submenu = menu ? menu->GetHMenu() : 0;
757 wxCHECK_MSG( submenu, FALSE, wxT("can't append invalid menu to menubar") );
758
759 if ( !wxMenuBarBase::Append(menu, title) )
760 return FALSE;
761
762 m_titles.Add(title);
763
764 UMASetMenuTitle( MAC_WXHMENU(menu->GetHMenu()) , title ) ;
765
766 if ( IsAttached() )
767 {
768 if (s_macInstalledMenuBar == this)
769 {
770 ::InsertMenu( MAC_WXHMENU(menu->GetHMenu()) , 0 ) ;
771 }
772
773 Refresh();
774 }
775
776 // m_invokingWindow is set after wxFrame::SetMenuBar(). This call enables
777 // adding menu later on.
778 if (m_invokingWindow)
779 wxMenubarSetInvokingWindow( menu, m_invokingWindow );
780
781 return TRUE;
782 }
783
784 static void wxMenubarUnsetInvokingWindow( wxMenu *menu )
785 {
786 menu->SetInvokingWindow( (wxWindow*) NULL );
787
788 wxMenuItemList::Node *node = menu->GetMenuItems().GetFirst();
789 while (node)
790 {
791 wxMenuItem *menuitem = node->GetData();
792 if (menuitem->IsSubMenu())
793 wxMenubarUnsetInvokingWindow( menuitem->GetSubMenu() );
794 node = node->GetNext();
795 }
796 }
797
798 static void wxMenubarSetInvokingWindow( wxMenu *menu, wxWindow *win )
799 {
800 menu->SetInvokingWindow( win );
801
802 wxMenuItemList::Node *node = menu->GetMenuItems().GetFirst();
803 while (node)
804 {
805 wxMenuItem *menuitem = node->GetData();
806 if (menuitem->IsSubMenu())
807 wxMenubarSetInvokingWindow( menuitem->GetSubMenu() , win );
808 node = node->GetNext();
809 }
810 }
811
812 void wxMenuBar::UnsetInvokingWindow()
813 {
814 m_invokingWindow = (wxWindow*) NULL;
815 wxMenuList::Node *node = m_menus.GetFirst();
816 while (node)
817 {
818 wxMenu *menu = node->GetData();
819 wxMenubarUnsetInvokingWindow( menu );
820 node = node->GetNext();
821 }
822 }
823
824 void wxMenuBar::SetInvokingWindow(wxFrame *frame)
825 {
826 m_invokingWindow = frame;
827 wxMenuList::Node *node = m_menus.GetFirst();
828 while (node)
829 {
830 wxMenu *menu = node->GetData();
831 wxMenubarSetInvokingWindow( menu, frame );
832 node = node->GetNext();
833 }
834 }
835
836 void wxMenuBar::Detach()
837 {
838 wxMenuBarBase::Detach() ;
839 }
840
841 void wxMenuBar::Attach(wxFrame *frame)
842 {
843 wxMenuBarBase::Attach( frame ) ;
844 }
845 // ---------------------------------------------------------------------------
846 // wxMenuBar searching for menu items
847 // ---------------------------------------------------------------------------
848
849 // Find the itemString in menuString, and return the item id or wxNOT_FOUND
850 int wxMenuBar::FindMenuItem(const wxString& menuString,
851 const wxString& itemString) const
852 {
853 wxString menuLabel = wxStripMenuCodes(menuString);
854 size_t count = GetMenuCount();
855 for ( size_t i = 0; i < count; i++ )
856 {
857 wxString title = wxStripMenuCodes(m_titles[i]);
858 if ( menuString == title )
859 return m_menus[i]->FindItem(itemString);
860 }
861
862 return wxNOT_FOUND;
863 }
864
865 wxMenuItem *wxMenuBar::FindItem(int id, wxMenu **itemMenu) const
866 {
867 if ( itemMenu )
868 *itemMenu = NULL;
869
870 wxMenuItem *item = NULL;
871 size_t count = GetMenuCount();
872 for ( size_t i = 0; !item && (i < count); i++ )
873 {
874 item = m_menus[i]->FindItem(id, itemMenu);
875 }
876
877 return item;
878 }
879
880