]> git.saurik.com Git - wxWidgets.git/blob - src/mac/carbon/menu.cpp
MPThread implementation by AJ Lavin
[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, wxFont::GetDefaultEncoding() );
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() == GetMenuBar())
128 {
129 pSubMenu->MacBeforeDisplay( true ) ;
130 }
131
132 if ( pos == (size_t)-1 )
133 UMAAppendSubMenuItem(MAC_WXHMENU(m_hMenu), pItem->GetText(), wxFont::GetDefaultEncoding() , pSubMenu->m_macMenuId);
134 else
135 UMAInsertSubMenuItem(MAC_WXHMENU(m_hMenu), pItem->GetText(), wxFont::GetDefaultEncoding() , 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") , wxFont::GetDefaultEncoding() );
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"), wxFont::GetDefaultEncoding(), 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 GetMenuBar()->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 wxMenuItem* wxMenu::DoAppend(wxMenuItem *item)
181 {
182 wxCHECK_MSG( item, NULL, _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 NULL;
226 }
227
228 if ( check )
229 {
230 // check the item initially
231 item->Check(TRUE);
232 }
233
234 return item;
235 }
236
237 wxMenuItem* wxMenu::DoInsert(size_t pos, wxMenuItem *item)
238 {
239 if (wxMenuBase::DoInsert(pos, item) && DoInsertOrAppend(item, pos))
240 return item;
241 else
242 return NULL;
243 }
244
245 wxMenuItem *wxMenu::DoRemove(wxMenuItem *item)
246 {
247 // we need to find the items position in the child list
248 size_t pos;
249 wxMenuItemList::Node *node = GetMenuItems().GetFirst();
250 for ( pos = 0; node; pos++ )
251 {
252 if ( node->GetData() == item )
253 break;
254
255 node = node->GetNext();
256 }
257
258 // DoRemove() (unlike Remove) can only be called for existing item!
259 wxCHECK_MSG( node, NULL, wxT("bug in wxMenu::Remove logic") );
260
261 ::DeleteMenuItem(MAC_WXHMENU(m_hMenu) , pos + 1);
262
263 if ( IsAttached() )
264 {
265 // otherwise, the change won't be visible
266 GetMenuBar()->Refresh();
267 }
268
269 // and from internal data structures
270 return wxMenuBase::DoRemove(item);
271 }
272
273 void wxMenu::SetTitle(const wxString& label)
274 {
275 m_title = label ;
276 UMASetMenuTitle(MAC_WXHMENU(m_hMenu) , label , wxFont::GetDefaultEncoding() ) ;
277 }
278 bool wxMenu::ProcessCommand(wxCommandEvent & event)
279 {
280 bool processed = FALSE;
281
282 // Try the menu's event handler
283 if ( !processed && GetEventHandler())
284 {
285 processed = GetEventHandler()->ProcessEvent(event);
286 }
287
288 // Try the window the menu was popped up from (and up through the
289 // hierarchy)
290 wxWindow *win = GetInvokingWindow();
291 if ( !processed && win )
292 processed = win->GetEventHandler()->ProcessEvent(event);
293
294 return processed;
295 }
296
297
298 // ---------------------------------------------------------------------------
299 // other
300 // ---------------------------------------------------------------------------
301
302 wxWindow *wxMenu::GetWindow() const
303 {
304 if ( m_invokingWindow != NULL )
305 return m_invokingWindow;
306 else if ( GetMenuBar() != NULL)
307 return (wxWindow *) GetMenuBar()->GetFrame();
308
309 return NULL;
310 }
311
312 // helper functions returning the mac menu position for a certain item, note that this is
313 // mac-wise 1 - based, i.e. the first item has index 1 whereas on MSWin it has pos 0
314
315 int wxMenu::MacGetIndexFromId( int id )
316 {
317 size_t pos;
318 wxMenuItemList::Node *node = GetMenuItems().GetFirst();
319 for ( pos = 0; node; pos++ )
320 {
321 if ( node->GetData()->GetId() == id )
322 break;
323
324 node = node->GetNext();
325 }
326
327 if (!node)
328 return 0;
329
330 return pos + 1 ;
331 }
332
333 int wxMenu::MacGetIndexFromItem( wxMenuItem *pItem )
334 {
335 size_t pos;
336 wxMenuItemList::Node *node = GetMenuItems().GetFirst();
337 for ( pos = 0; node; pos++ )
338 {
339 if ( node->GetData() == pItem )
340 break;
341
342 node = node->GetNext();
343 }
344
345 if (!node)
346 return 0;
347
348 return pos + 1 ;
349 }
350
351 void wxMenu::MacEnableMenu( bool bDoEnable )
352 {
353 UMAEnableMenuItem(MAC_WXHMENU(m_hMenu) , 0 , bDoEnable ) ;
354
355 ::DrawMenuBar() ;
356 }
357
358 // MacOS needs to know about submenus somewhere within this menu
359 // before it can be displayed , also hide special menu items like preferences
360 // that are handled by the OS
361 void wxMenu::MacBeforeDisplay( bool isSubMenu )
362 {
363 wxMenuItem* previousItem = NULL ;
364 size_t pos ;
365 wxMenuItemList::Node *node;
366 wxMenuItem *item;
367 for (pos = 0, node = GetMenuItems().GetFirst(); node; node = node->GetNext(), pos++)
368 {
369 item = (wxMenuItem *)node->GetData();
370 wxMenu* subMenu = item->GetSubMenu() ;
371 if (subMenu)
372 {
373 subMenu->MacBeforeDisplay( true ) ;
374 }
375 else
376 {
377 #if TARGET_CARBON
378 if ( UMAGetSystemVersion() >= 0x1000 )
379 {
380 if ( item->GetId() == wxApp::s_macPreferencesMenuItemId || item->GetId() == wxApp::s_macExitMenuItemId)
381 {
382 ChangeMenuItemAttributes( MAC_WXHMENU( GetHMenu() ) , pos + 1, kMenuItemAttrHidden, 0 );
383 if ( GetMenuItems().GetCount() == pos + 1 &&
384 previousItem != NULL &&
385 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 wxMenuBar* wxMenuBar::s_macCommonMenuBar = NULL ;
447
448 void wxMenuBar::Init()
449 {
450 m_eventHandler = this;
451 m_menuBarFrame = NULL;
452 m_invokingWindow = (wxWindow*) NULL;
453 }
454
455 wxMenuBar::wxMenuBar()
456 {
457 Init();
458 }
459
460 wxMenuBar::wxMenuBar( long WXUNUSED(style) )
461 {
462 Init();
463 }
464
465
466 wxMenuBar::wxMenuBar(int count, wxMenu *menus[], const wxString titles[])
467 {
468 Init();
469
470 m_titles.Alloc(count);
471
472 for ( int i = 0; i < count; i++ )
473 {
474 m_menus.Append(menus[i]);
475 m_titles.Add(titles[i]);
476
477 menus[i]->Attach(this);
478 }
479 }
480
481 wxMenuBar::~wxMenuBar()
482 {
483 if (s_macCommonMenuBar == this)
484 s_macCommonMenuBar = NULL;
485 if (s_macInstalledMenuBar == this)
486 {
487 ::ClearMenuBar();
488 s_macInstalledMenuBar = NULL;
489 }
490
491 }
492
493 void wxMenuBar::Refresh(bool WXUNUSED(eraseBackground), const wxRect *WXUNUSED(rect))
494 {
495 wxCHECK_RET( IsAttached(), wxT("can't refresh unatteched menubar") );
496
497 DrawMenuBar();
498 }
499
500 void wxMenuBar::MacInstallMenuBar()
501 {
502 if ( s_macInstalledMenuBar == this )
503 return ;
504
505 wxStAppResource resload ;
506
507 MenuBarHandle menubar = NewHandleClear( sizeof( MenuBarHeader ) ) ;
508 ::SetMenuBar( menubar ) ;
509 DisposeMenuBar( menubar ) ;
510
511 // clean-up the help menu before adding new items
512 MenuHandle mh = NULL ;
513 if ( UMAGetHelpMenu( &mh , &firstUserHelpMenuItem) == noErr )
514 {
515 for ( int i = CountMenuItems( mh ) ; i >= firstUserHelpMenuItem ; --i )
516 {
517 DeleteMenuItem( mh , i ) ;
518 }
519 }
520 else
521 {
522 mh = NULL ;
523 }
524 #if TARGET_CARBON
525 if ( UMAGetSystemVersion() >= 0x1000 && wxApp::s_macPreferencesMenuItemId)
526 {
527 wxMenuItem *item = FindItem( wxApp::s_macPreferencesMenuItemId , NULL ) ;
528 if ( item == NULL || !(item->IsEnabled()) )
529 DisableMenuCommand( NULL , kHICommandPreferences ) ;
530 else
531 EnableMenuCommand( NULL , kHICommandPreferences ) ;
532 }
533 #endif
534 for (size_t i = 0; i < m_menus.GetCount(); i++)
535 {
536 wxMenuItemList::Node *node;
537 wxMenuItem *item;
538 int pos ;
539 wxMenu* menu = m_menus[i] , *subMenu = NULL ;
540
541 if( m_titles[i] == wxT("?") || m_titles[i] == wxT("&?") || m_titles[i] == wxApp::s_macHelpMenuTitleName )
542 {
543 if ( mh == NULL )
544 {
545 continue ;
546 }
547
548 for (pos = 0 , node = menu->GetMenuItems().GetFirst(); node; node = node->GetNext(), pos++)
549 {
550 item = (wxMenuItem *)node->GetData();
551 subMenu = item->GetSubMenu() ;
552 if (subMenu)
553 {
554 // we don't support hierarchical menus in the help menu yet
555 }
556 else
557 {
558 if ( item->IsSeparator() )
559 {
560 if ( mh )
561 MacAppendMenu(mh, "\p-" );
562 }
563 else
564 {
565 wxAcceleratorEntry* entry = wxGetAccelFromString( item->GetText() ) ;
566
567 if ( item->GetId() == wxApp::s_macAboutMenuItemId )
568 {
569 UMASetMenuItemText( GetMenuHandle( kwxMacAppleMenuId ) , 1 , item->GetText() , wxFont::GetDefaultEncoding() );
570 UMAEnableMenuItem( GetMenuHandle( kwxMacAppleMenuId ) , 1 , true );
571 SetMenuItemCommandID( GetMenuHandle( kwxMacAppleMenuId ) , 1 , item->GetId() ) ;
572 UMASetMenuItemShortcut( GetMenuHandle( kwxMacAppleMenuId ) , 1 , entry ) ;
573 }
574 else
575 {
576 if ( mh )
577 {
578 UMAAppendMenuItem(mh, item->GetText() , wxFont::GetDefaultEncoding(), entry);
579 SetMenuItemCommandID( mh , CountMenuItems(mh) , item->GetId() ) ;
580 }
581 }
582
583 delete entry ;
584 }
585 }
586 }
587 }
588 else
589 {
590 UMASetMenuTitle( MAC_WXHMENU(menu->GetHMenu()) , m_titles[i], m_font.GetEncoding() ) ;
591 m_menus[i]->MacBeforeDisplay(false) ;
592 ::InsertMenu(MAC_WXHMENU(m_menus[i]->GetHMenu()), 0);
593 }
594 }
595 ::DrawMenuBar() ;
596 s_macInstalledMenuBar = this;
597 }
598
599 void wxMenuBar::EnableTop(size_t pos, bool enable)
600 {
601 wxCHECK_RET( IsAttached(), wxT("doesn't work with unattached menubars") );
602 m_menus[pos]->MacEnableMenu( enable ) ;
603 Refresh();
604 }
605
606 bool wxMenuBar::Enable( bool enable)
607 {
608 wxCHECK_MSG( IsAttached(), false, wxT("doesn't work with unattached menubars") );
609 size_t i;
610 for (i = 0; i < GetMenuCount(); i++)
611 {
612 EnableTop(i, enable);
613 }
614 return true;
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 , m_font.GetEncoding() ) ;
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 , m_font.GetEncoding() ) ;
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 , m_font.GetEncoding() ) ;
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 ( menuLabel == 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