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