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