]> git.saurik.com Git - wxWidgets.git/blob - src/mac/carbon/menu.cpp
Fix DoGetBestSize when wxCB_READONLY is used. The best size of the
[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 = NULL ;
508 #if TARGET_API_MAC_OSX
509 menubar = NewHandleClear( 6 /* sizeof( MenuBarHeader ) */ ) ;
510 #else
511 menubar = NewHandleClear( 12 ) ;
512 (*menubar)[3] = 0x0a ;
513 #endif
514 ::SetMenuBar( menubar ) ;
515 DisposeMenuBar( menubar ) ;
516 MenuHandle appleMenu = NULL ;
517 char appleMenuTitle[3] = { 01 , kMenuAppleLogoFilledGlyph , 0 } ;
518
519 verify_noerr( CreateNewMenu( kwxMacAppleMenuId , 0 , &appleMenu ) ) ;
520 verify_noerr( SetMenuTitle( appleMenu , (ConstStr255Param) appleMenuTitle ) );
521 MacInsertMenuItem( appleMenu , "\pAbout..." , 0 ) ;
522 MacInsertMenu( appleMenu , 0 ) ;
523
524 // clean-up the help menu before adding new items
525 MenuHandle mh = NULL ;
526 if ( UMAGetHelpMenu( &mh , &firstUserHelpMenuItem) == noErr )
527 {
528 for ( int i = CountMenuItems( mh ) ; i >= firstUserHelpMenuItem ; --i )
529 {
530 DeleteMenuItem( mh , i ) ;
531 }
532 }
533 else
534 {
535 mh = NULL ;
536 }
537 #if TARGET_CARBON
538 if ( UMAGetSystemVersion() >= 0x1000 && wxApp::s_macPreferencesMenuItemId)
539 {
540 wxMenuItem *item = FindItem( wxApp::s_macPreferencesMenuItemId , NULL ) ;
541 if ( item == NULL || !(item->IsEnabled()) )
542 DisableMenuCommand( NULL , kHICommandPreferences ) ;
543 else
544 EnableMenuCommand( NULL , kHICommandPreferences ) ;
545 }
546 #endif
547 for (size_t i = 0; i < m_menus.GetCount(); i++)
548 {
549 wxMenuItemList::Node *node;
550 wxMenuItem *item;
551 int pos ;
552 wxMenu* menu = m_menus[i] , *subMenu = NULL ;
553
554 if( m_titles[i] == wxT("?") || m_titles[i] == wxT("&?") || m_titles[i] == wxApp::s_macHelpMenuTitleName )
555 {
556 if ( mh == NULL )
557 {
558 continue ;
559 }
560
561 for (pos = 0 , node = menu->GetMenuItems().GetFirst(); node; node = node->GetNext(), pos++)
562 {
563 item = (wxMenuItem *)node->GetData();
564 subMenu = item->GetSubMenu() ;
565 if (subMenu)
566 {
567 // we don't support hierarchical menus in the help menu yet
568 }
569 else
570 {
571 if ( item->IsSeparator() )
572 {
573 if ( mh )
574 MacAppendMenu(mh, "\p-" );
575 }
576 else
577 {
578 wxAcceleratorEntry* entry = wxGetAccelFromString( item->GetText() ) ;
579
580 if ( item->GetId() == wxApp::s_macAboutMenuItemId )
581 {
582 UMASetMenuItemText( GetMenuHandle( kwxMacAppleMenuId ) , 1 , item->GetText() , wxFont::GetDefaultEncoding() );
583 UMAEnableMenuItem( GetMenuHandle( kwxMacAppleMenuId ) , 1 , true );
584 SetMenuItemCommandID( GetMenuHandle( kwxMacAppleMenuId ) , 1 , item->GetId() ) ;
585 UMASetMenuItemShortcut( GetMenuHandle( kwxMacAppleMenuId ) , 1 , entry ) ;
586 }
587 else
588 {
589 if ( mh )
590 {
591 UMAAppendMenuItem(mh, item->GetText() , wxFont::GetDefaultEncoding(), entry);
592 SetMenuItemCommandID( mh , CountMenuItems(mh) , item->GetId() ) ;
593 }
594 }
595
596 delete entry ;
597 }
598 }
599 }
600 }
601 else
602 {
603 UMASetMenuTitle( MAC_WXHMENU(menu->GetHMenu()) , m_titles[i], m_font.GetEncoding() ) ;
604 m_menus[i]->MacBeforeDisplay(false) ;
605 ::InsertMenu(MAC_WXHMENU(m_menus[i]->GetHMenu()), 0);
606 }
607 }
608 ::DrawMenuBar() ;
609 s_macInstalledMenuBar = this;
610 }
611
612 void wxMenuBar::EnableTop(size_t pos, bool enable)
613 {
614 wxCHECK_RET( IsAttached(), wxT("doesn't work with unattached menubars") );
615 m_menus[pos]->MacEnableMenu( enable ) ;
616 Refresh();
617 }
618
619 bool wxMenuBar::Enable( bool enable)
620 {
621 wxCHECK_MSG( IsAttached(), false, wxT("doesn't work with unattached menubars") );
622 size_t i;
623 for (i = 0; i < GetMenuCount(); i++)
624 {
625 EnableTop(i, enable);
626 }
627 return true;
628 }
629
630 void wxMenuBar::SetLabelTop(size_t pos, const wxString& label)
631 {
632 wxCHECK_RET( pos < GetMenuCount(), wxT("invalid menu index") );
633
634 m_titles[pos] = label;
635
636 if ( !IsAttached() )
637 {
638 return;
639 }
640
641 m_menus[pos]->SetTitle( label ) ;
642 if (wxMenuBar::s_macInstalledMenuBar == this) // are we currently installed ?
643 {
644 ::SetMenuBar( GetMenuBar() ) ;
645 ::InvalMenuBar() ;
646 }
647 }
648
649 wxString wxMenuBar::GetLabelTop(size_t pos) const
650 {
651 wxCHECK_MSG( pos < GetMenuCount(), wxEmptyString,
652 wxT("invalid menu index in wxMenuBar::GetLabelTop") );
653
654 return m_titles[pos];
655 }
656
657 int wxMenuBar::FindMenu(const wxString& title)
658 {
659 wxString menuTitle = wxStripMenuCodes(title);
660
661 size_t count = GetMenuCount();
662 for ( size_t i = 0; i < count; i++ )
663 {
664 wxString title = wxStripMenuCodes(m_titles[i]);
665 if ( menuTitle == title )
666 return i;
667 }
668
669 return wxNOT_FOUND;
670
671 }
672
673
674 // ---------------------------------------------------------------------------
675 // wxMenuBar construction
676 // ---------------------------------------------------------------------------
677
678 // ---------------------------------------------------------------------------
679 // wxMenuBar construction
680 // ---------------------------------------------------------------------------
681
682 wxMenu *wxMenuBar::Replace(size_t pos, wxMenu *menu, const wxString& title)
683 {
684 wxMenu *menuOld = wxMenuBarBase::Replace(pos, menu, title);
685 if ( !menuOld )
686 return FALSE;
687 m_titles[pos] = title;
688
689 if ( IsAttached() )
690 {
691 if (s_macInstalledMenuBar == this)
692 {
693 menuOld->MacAfterDisplay( false ) ;
694 ::DeleteMenu( menuOld->MacGetMenuId() /* m_menus[pos]->MacGetMenuId() */ ) ;
695 {
696 menu->MacBeforeDisplay( false ) ;
697 UMASetMenuTitle( MAC_WXHMENU(menu->GetHMenu()) , title , m_font.GetEncoding() ) ;
698 if ( pos == m_menus.GetCount() - 1)
699 {
700 ::InsertMenu( MAC_WXHMENU(menu->GetHMenu()) , 0 ) ;
701 }
702 else
703 {
704 ::InsertMenu( MAC_WXHMENU(menu->GetHMenu()) , m_menus[pos+1]->MacGetMenuId() ) ;
705 }
706 }
707 }
708
709 Refresh();
710 }
711
712 return menuOld;
713 }
714
715 bool wxMenuBar::Insert(size_t pos, wxMenu *menu, const wxString& title)
716 {
717 if ( !wxMenuBarBase::Insert(pos, menu, title) )
718 return FALSE;
719
720 m_titles.Insert(title, pos);
721
722 UMASetMenuTitle( MAC_WXHMENU(menu->GetHMenu()) , title , m_font.GetEncoding() ) ;
723
724 if ( IsAttached() && s_macInstalledMenuBar == this )
725 {
726 if (s_macInstalledMenuBar == this)
727 {
728 menu->MacBeforeDisplay( false ) ;
729 if ( pos == (size_t) -1 || pos + 1 == m_menus.GetCount() )
730 {
731 ::InsertMenu( MAC_WXHMENU(menu->GetHMenu()) , 0 ) ;
732 }
733 else
734 {
735 ::InsertMenu( MAC_WXHMENU(menu->GetHMenu()) , m_menus[pos+1]->MacGetMenuId() ) ;
736 }
737 }
738 Refresh();
739 }
740
741 return TRUE;
742 }
743
744 wxMenu *wxMenuBar::Remove(size_t pos)
745 {
746 wxMenu *menu = wxMenuBarBase::Remove(pos);
747 if ( !menu )
748 return NULL;
749
750 if ( IsAttached() )
751 {
752 if (s_macInstalledMenuBar == this)
753 {
754 ::DeleteMenu( menu->MacGetMenuId() /* m_menus[pos]->MacGetMenuId() */ ) ;
755 }
756
757 Refresh();
758 }
759
760 m_titles.RemoveAt(pos);
761
762 return menu;
763 }
764
765 bool wxMenuBar::Append(wxMenu *menu, const wxString& title)
766 {
767 WXHMENU submenu = menu ? menu->GetHMenu() : 0;
768 wxCHECK_MSG( submenu, FALSE, wxT("can't append invalid menu to menubar") );
769
770 if ( !wxMenuBarBase::Append(menu, title) )
771 return FALSE;
772
773 m_titles.Add(title);
774
775 UMASetMenuTitle( MAC_WXHMENU(menu->GetHMenu()) , title , m_font.GetEncoding() ) ;
776
777 if ( IsAttached() )
778 {
779 if (s_macInstalledMenuBar == this)
780 {
781 ::InsertMenu( MAC_WXHMENU(menu->GetHMenu()) , 0 ) ;
782 }
783
784 Refresh();
785 }
786
787 // m_invokingWindow is set after wxFrame::SetMenuBar(). This call enables
788 // adding menu later on.
789 if (m_invokingWindow)
790 wxMenubarSetInvokingWindow( menu, m_invokingWindow );
791
792 return TRUE;
793 }
794
795 static void wxMenubarUnsetInvokingWindow( wxMenu *menu )
796 {
797 menu->SetInvokingWindow( (wxWindow*) NULL );
798
799 wxMenuItemList::Node *node = menu->GetMenuItems().GetFirst();
800 while (node)
801 {
802 wxMenuItem *menuitem = node->GetData();
803 if (menuitem->IsSubMenu())
804 wxMenubarUnsetInvokingWindow( menuitem->GetSubMenu() );
805 node = node->GetNext();
806 }
807 }
808
809 static void wxMenubarSetInvokingWindow( wxMenu *menu, wxWindow *win )
810 {
811 menu->SetInvokingWindow( win );
812
813 wxMenuItemList::Node *node = menu->GetMenuItems().GetFirst();
814 while (node)
815 {
816 wxMenuItem *menuitem = node->GetData();
817 if (menuitem->IsSubMenu())
818 wxMenubarSetInvokingWindow( menuitem->GetSubMenu() , win );
819 node = node->GetNext();
820 }
821 }
822
823 void wxMenuBar::UnsetInvokingWindow()
824 {
825 m_invokingWindow = (wxWindow*) NULL;
826 wxMenuList::Node *node = m_menus.GetFirst();
827 while (node)
828 {
829 wxMenu *menu = node->GetData();
830 wxMenubarUnsetInvokingWindow( menu );
831 node = node->GetNext();
832 }
833 }
834
835 void wxMenuBar::SetInvokingWindow(wxFrame *frame)
836 {
837 m_invokingWindow = frame;
838 wxMenuList::Node *node = m_menus.GetFirst();
839 while (node)
840 {
841 wxMenu *menu = node->GetData();
842 wxMenubarSetInvokingWindow( menu, frame );
843 node = node->GetNext();
844 }
845 }
846
847 void wxMenuBar::Detach()
848 {
849 wxMenuBarBase::Detach() ;
850 }
851
852 void wxMenuBar::Attach(wxFrame *frame)
853 {
854 wxMenuBarBase::Attach( frame ) ;
855 }
856 // ---------------------------------------------------------------------------
857 // wxMenuBar searching for menu items
858 // ---------------------------------------------------------------------------
859
860 // Find the itemString in menuString, and return the item id or wxNOT_FOUND
861 int wxMenuBar::FindMenuItem(const wxString& menuString,
862 const wxString& itemString) const
863 {
864 wxString menuLabel = wxStripMenuCodes(menuString);
865 size_t count = GetMenuCount();
866 for ( size_t i = 0; i < count; i++ )
867 {
868 wxString title = wxStripMenuCodes(m_titles[i]);
869 if ( menuLabel == title )
870 return m_menus[i]->FindItem(itemString);
871 }
872
873 return wxNOT_FOUND;
874 }
875
876 wxMenuItem *wxMenuBar::FindItem(int id, wxMenu **itemMenu) const
877 {
878 if ( itemMenu )
879 *itemMenu = NULL;
880
881 wxMenuItem *item = NULL;
882 size_t count = GetMenuCount();
883 for ( size_t i = 0; !item && (i < count); i++ )
884 {
885 item = m_menus[i]->FindItem(id, itemMenu);
886 }
887
888 return item;
889 }
890
891