]> git.saurik.com Git - wxWidgets.git/blob - src/mac/carbon/menu.cpp
who knows, maybe this will fix the 10.3 problems
[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 // normal item
410 {
411 #if TARGET_CARBON
412 if ( UMAGetSystemVersion() >= 0x1000 )
413 {
414 // what we do here is to hide the special items which are
415 // shown in the application menu anyhow -- it doesn't make
416 // sense to show them in their normal place as well
417 if ( item->GetId() == wxApp::s_macPreferencesMenuItemId ||
418 item->GetId() == wxApp::s_macExitMenuItemId )
419 {
420 ChangeMenuItemAttributes( MAC_WXHMENU( GetHMenu() ),
421 pos + 1, kMenuItemAttrHidden, 0 );
422
423 // also check for a separator which was used just to
424 // separate this item from the others, so don't leave
425 // separator at the menu start or end nor 2 consecutive
426 // separators
427 wxMenuItemList::Node *nextNode = node->GetNext();
428 wxMenuItem *next = nextNode ? nextNode->GetData() : NULL;
429
430 size_t posSeptoHide;
431 if ( !previousItem && next && next->IsSeparator() )
432 {
433 // next (i.e. second as we must be first) item is
434 // the separator to hide
435 wxASSERT_MSG( pos == 0, _T("should be the menu start") );
436 posSeptoHide = 2;
437 }
438 else if ( GetMenuItems().GetCount() == pos + 1 &&
439 previousItem != NULL &&
440 previousItem->IsSeparator() )
441 {
442 // prev item is a trailing separator we want to hide
443 posSeptoHide = pos;
444 }
445 else if ( previousItem && previousItem->IsSeparator() &&
446 next && next->IsSeparator() )
447 {
448 // two consecutive separators, this is one too many
449 posSeptoHide = pos;
450 }
451 else // no separators to hide
452 {
453 posSeptoHide = 0;
454 }
455
456 if ( posSeptoHide )
457 {
458 // hide the separator as well
459 ChangeMenuItemAttributes( MAC_WXHMENU( GetHMenu() ),
460 posSeptoHide,
461 kMenuItemAttrHidden,
462 0 );
463 }
464 }
465 }
466 #endif // TARGET_CARBON
467 }
468 previousItem = item ;
469 }
470
471 if ( isSubMenu )
472 ::InsertMenu(MAC_WXHMENU( GetHMenu()), -1);
473
474 }
475 // undo all changes from the MacBeforeDisplay call
476 void wxMenu::MacAfterDisplay( bool isSubMenu )
477 {
478 if ( isSubMenu )
479 ::DeleteMenu(MacGetMenuId());
480
481 wxMenuItem* previousItem = NULL ;
482 int pos ;
483 wxMenuItemList::Node *node;
484 wxMenuItem *item;
485 for (pos = 0, node = GetMenuItems().GetFirst(); node; node = node->GetNext(), pos++)
486 {
487 item = (wxMenuItem *)node->GetData();
488 wxMenu* subMenu = item->GetSubMenu() ;
489 if (subMenu)
490 {
491 subMenu->MacAfterDisplay( true ) ;
492 }
493 else
494 {
495 // no need to undo hidings
496 }
497 previousItem = item ;
498 }
499 }
500
501 // Menu Bar
502
503 /*
504
505 Mac Implementation note :
506
507 The Mac has only one global menubar, so we attempt to install the currently
508 active menubar from a frame, we currently don't take into account mdi-frames
509 which would ask for menu-merging
510
511 Secondly there is no mac api for changing a menubar that is not the current
512 menubar, so we have to wait for preparing the actual menubar until the
513 wxMenubar is to be used
514
515 We can in subsequent versions use MacInstallMenuBar to provide some sort of
516 auto-merge for MDI in case this will be necessary
517
518 */
519
520 wxMenuBar* wxMenuBar::s_macInstalledMenuBar = NULL ;
521 wxMenuBar* wxMenuBar::s_macCommonMenuBar = NULL ;
522
523 void wxMenuBar::Init()
524 {
525 m_eventHandler = this;
526 m_menuBarFrame = NULL;
527 m_invokingWindow = (wxWindow*) NULL;
528 }
529
530 wxMenuBar::wxMenuBar()
531 {
532 Init();
533 }
534
535 wxMenuBar::wxMenuBar( long WXUNUSED(style) )
536 {
537 Init();
538 }
539
540
541 wxMenuBar::wxMenuBar(int count, wxMenu *menus[], const wxString titles[])
542 {
543 Init();
544
545 m_titles.Alloc(count);
546
547 for ( int i = 0; i < count; i++ )
548 {
549 m_menus.Append(menus[i]);
550 m_titles.Add(titles[i]);
551
552 menus[i]->Attach(this);
553 }
554 }
555
556 wxMenuBar::~wxMenuBar()
557 {
558 if (s_macCommonMenuBar == this)
559 s_macCommonMenuBar = NULL;
560 if (s_macInstalledMenuBar == this)
561 {
562 ::ClearMenuBar();
563 s_macInstalledMenuBar = NULL;
564 }
565
566 }
567
568 void wxMenuBar::Refresh(bool WXUNUSED(eraseBackground), const wxRect *WXUNUSED(rect))
569 {
570 wxCHECK_RET( IsAttached(), wxT("can't refresh unatteched menubar") );
571
572 DrawMenuBar();
573 }
574
575 void wxMenuBar::MacInstallMenuBar()
576 {
577 if ( s_macInstalledMenuBar == this )
578 return ;
579
580 MenuBarHandle menubar = NULL ;
581 #if TARGET_API_MAC_OSX
582 menubar = NewHandleClear( 6 /* sizeof( MenuBarHeader ) */ ) ;
583 #else
584 menubar = NewHandleClear( 12 ) ;
585 (*menubar)[3] = 0x0a ;
586 #endif
587 ::SetMenuBar( menubar ) ;
588 DisposeMenuBar( menubar ) ;
589 MenuHandle appleMenu = NULL ;
590 char appleMenuTitle[3] = { 01 , kMenuAppleLogoFilledGlyph , 0 } ;
591
592 verify_noerr( CreateNewMenu( kwxMacAppleMenuId , 0 , &appleMenu ) ) ;
593 verify_noerr( SetMenuTitle( appleMenu , (ConstStr255Param) appleMenuTitle ) );
594
595 // Add About/Preferences separator only on OS X
596 // KH/RN: Separator is always present on 10.3 but not on 10.2
597 // However, the change from 10.2 to 10.3 suggests it is preferred
598 #if TARGET_API_MAC_OSX
599 MacInsertMenuItem( appleMenu , "\p-" , 0 ) ;
600 #endif
601
602 MacInsertMenuItem( appleMenu , "\pAbout..." , 0 ) ;
603 MacInsertMenu( appleMenu , 0 ) ;
604
605 // clean-up the help menu before adding new items
606 MenuHandle mh = NULL ;
607 if ( UMAGetHelpMenu( &mh , &firstUserHelpMenuItem) == noErr )
608 {
609 for ( int i = CountMenuItems( mh ) ; i >= firstUserHelpMenuItem ; --i )
610 {
611 DeleteMenuItem( mh , i ) ;
612 }
613 }
614 else
615 {
616 mh = NULL ;
617 }
618 #if TARGET_CARBON
619 if ( UMAGetSystemVersion() >= 0x1000 && wxApp::s_macPreferencesMenuItemId)
620 {
621 wxMenuItem *item = FindItem( wxApp::s_macPreferencesMenuItemId , NULL ) ;
622 if ( item == NULL || !(item->IsEnabled()) )
623 DisableMenuCommand( NULL , kHICommandPreferences ) ;
624 else
625 EnableMenuCommand( NULL , kHICommandPreferences ) ;
626 }
627 #endif
628 for (size_t i = 0; i < m_menus.GetCount(); i++)
629 {
630 wxMenuItemList::Node *node;
631 wxMenuItem *item;
632 int pos ;
633 wxMenu* menu = m_menus[i] , *subMenu = NULL ;
634
635 if( m_titles[i] == wxT("?") || m_titles[i] == wxT("&?") || m_titles[i] == wxApp::s_macHelpMenuTitleName )
636 {
637 if ( mh == NULL )
638 {
639 continue ;
640 }
641
642 for (pos = 0 , node = menu->GetMenuItems().GetFirst(); node; node = node->GetNext(), pos++)
643 {
644 item = (wxMenuItem *)node->GetData();
645 subMenu = item->GetSubMenu() ;
646 if (subMenu)
647 {
648 // we don't support hierarchical menus in the help menu yet
649 }
650 else
651 {
652 if ( item->IsSeparator() )
653 {
654 if ( mh )
655 MacAppendMenu(mh, "\p-" );
656 }
657 else
658 {
659 wxAcceleratorEntry* entry = wxGetAccelFromString( item->GetText() ) ;
660
661 if ( item->GetId() == wxApp::s_macAboutMenuItemId )
662 {
663 UMASetMenuItemText( GetMenuHandle( kwxMacAppleMenuId ) , 1 , item->GetText() , wxFont::GetDefaultEncoding() );
664 UMAEnableMenuItem( GetMenuHandle( kwxMacAppleMenuId ) , 1 , true );
665 SetMenuItemCommandID( GetMenuHandle( kwxMacAppleMenuId ) , 1 , item->GetId() ) ;
666 SetMenuItemRefCon(GetMenuHandle( kwxMacAppleMenuId ) , 1 , (UInt32)item ) ;
667 UMASetMenuItemShortcut( GetMenuHandle( kwxMacAppleMenuId ) , 1 , entry ) ;
668 }
669 else
670 {
671 if ( mh )
672 {
673 UMAAppendMenuItem(mh, item->GetText() , wxFont::GetDefaultEncoding(), entry);
674 SetMenuItemCommandID( mh , CountMenuItems(mh) , item->GetId() ) ;
675 SetMenuItemRefCon( mh , CountMenuItems(mh) , (UInt32)item ) ;
676 }
677 }
678
679 delete entry ;
680 }
681 }
682 }
683 }
684 else
685 {
686 UMASetMenuTitle( MAC_WXHMENU(menu->GetHMenu()) , m_titles[i], m_font.GetEncoding() ) ;
687 m_menus[i]->MacBeforeDisplay(false) ;
688 ::InsertMenu(MAC_WXHMENU(m_menus[i]->GetHMenu()), 0);
689 }
690 }
691 ::DrawMenuBar() ;
692 s_macInstalledMenuBar = this;
693 }
694
695 void wxMenuBar::EnableTop(size_t pos, bool enable)
696 {
697 wxCHECK_RET( IsAttached(), wxT("doesn't work with unattached menubars") );
698 m_menus[pos]->MacEnableMenu( enable ) ;
699 Refresh();
700 }
701
702 bool wxMenuBar::Enable( bool enable)
703 {
704 wxCHECK_MSG( IsAttached(), false, wxT("doesn't work with unattached menubars") );
705 size_t i;
706 for (i = 0; i < GetMenuCount(); i++)
707 {
708 EnableTop(i, enable);
709 }
710 return true;
711 }
712
713 void wxMenuBar::SetLabelTop(size_t pos, const wxString& label)
714 {
715 wxCHECK_RET( pos < GetMenuCount(), wxT("invalid menu index") );
716
717 m_titles[pos] = label;
718
719 if ( !IsAttached() )
720 {
721 return;
722 }
723
724 m_menus[pos]->SetTitle( label ) ;
725 if (wxMenuBar::s_macInstalledMenuBar == this) // are we currently installed ?
726 {
727 ::SetMenuBar( GetMenuBar() ) ;
728 ::InvalMenuBar() ;
729 }
730 }
731
732 wxString wxMenuBar::GetLabelTop(size_t pos) const
733 {
734 wxCHECK_MSG( pos < GetMenuCount(), wxEmptyString,
735 wxT("invalid menu index in wxMenuBar::GetLabelTop") );
736
737 return m_titles[pos];
738 }
739
740 int wxMenuBar::FindMenu(const wxString& title)
741 {
742 wxString menuTitle = wxStripMenuCodes(title);
743
744 size_t count = GetMenuCount();
745 for ( size_t i = 0; i < count; i++ )
746 {
747 wxString title = wxStripMenuCodes(m_titles[i]);
748 if ( menuTitle == title )
749 return i;
750 }
751
752 return wxNOT_FOUND;
753
754 }
755
756
757 // ---------------------------------------------------------------------------
758 // wxMenuBar construction
759 // ---------------------------------------------------------------------------
760
761 // ---------------------------------------------------------------------------
762 // wxMenuBar construction
763 // ---------------------------------------------------------------------------
764
765 wxMenu *wxMenuBar::Replace(size_t pos, wxMenu *menu, const wxString& title)
766 {
767 wxMenu *menuOld = wxMenuBarBase::Replace(pos, menu, title);
768 if ( !menuOld )
769 return FALSE;
770 m_titles[pos] = title;
771
772 if ( IsAttached() )
773 {
774 if (s_macInstalledMenuBar == this)
775 {
776 menuOld->MacAfterDisplay( false ) ;
777 ::DeleteMenu( menuOld->MacGetMenuId() /* m_menus[pos]->MacGetMenuId() */ ) ;
778 {
779 menu->MacBeforeDisplay( false ) ;
780 UMASetMenuTitle( MAC_WXHMENU(menu->GetHMenu()) , title , m_font.GetEncoding() ) ;
781 if ( pos == m_menus.GetCount() - 1)
782 {
783 ::InsertMenu( MAC_WXHMENU(menu->GetHMenu()) , 0 ) ;
784 }
785 else
786 {
787 ::InsertMenu( MAC_WXHMENU(menu->GetHMenu()) , m_menus[pos+1]->MacGetMenuId() ) ;
788 }
789 }
790 }
791
792 Refresh();
793 }
794 if (m_invokingWindow)
795 wxMenubarSetInvokingWindow( menu, m_invokingWindow );
796
797 return menuOld;
798 }
799
800 bool wxMenuBar::Insert(size_t pos, wxMenu *menu, const wxString& title)
801 {
802 if ( !wxMenuBarBase::Insert(pos, menu, title) )
803 return FALSE;
804
805 m_titles.Insert(title, pos);
806
807 UMASetMenuTitle( MAC_WXHMENU(menu->GetHMenu()) , title , m_font.GetEncoding() ) ;
808
809 if ( IsAttached() && s_macInstalledMenuBar == this )
810 {
811 if (s_macInstalledMenuBar == this)
812 {
813 menu->MacBeforeDisplay( false ) ;
814 if ( pos == (size_t) -1 || pos + 1 == m_menus.GetCount() )
815 {
816 ::InsertMenu( MAC_WXHMENU(menu->GetHMenu()) , 0 ) ;
817 }
818 else
819 {
820 ::InsertMenu( MAC_WXHMENU(menu->GetHMenu()) , m_menus[pos+1]->MacGetMenuId() ) ;
821 }
822 }
823 Refresh();
824 }
825 if (m_invokingWindow)
826 wxMenubarSetInvokingWindow( menu, m_invokingWindow );
827
828 return TRUE;
829 }
830
831 wxMenu *wxMenuBar::Remove(size_t pos)
832 {
833 wxMenu *menu = wxMenuBarBase::Remove(pos);
834 if ( !menu )
835 return NULL;
836
837 if ( IsAttached() )
838 {
839 if (s_macInstalledMenuBar == this)
840 {
841 ::DeleteMenu( menu->MacGetMenuId() /* m_menus[pos]->MacGetMenuId() */ ) ;
842 }
843
844 Refresh();
845 }
846
847 m_titles.RemoveAt(pos);
848
849 return menu;
850 }
851
852 bool wxMenuBar::Append(wxMenu *menu, const wxString& title)
853 {
854 WXHMENU submenu = menu ? menu->GetHMenu() : 0;
855 wxCHECK_MSG( submenu, FALSE, wxT("can't append invalid menu to menubar") );
856
857 if ( !wxMenuBarBase::Append(menu, title) )
858 return FALSE;
859
860 m_titles.Add(title);
861
862 UMASetMenuTitle( MAC_WXHMENU(menu->GetHMenu()) , title , m_font.GetEncoding() ) ;
863
864 if ( IsAttached() )
865 {
866 if (s_macInstalledMenuBar == this)
867 {
868 ::InsertMenu( MAC_WXHMENU(menu->GetHMenu()) , 0 ) ;
869 }
870
871 Refresh();
872 }
873
874 // m_invokingWindow is set after wxFrame::SetMenuBar(). This call enables
875 // adding menu later on.
876 if (m_invokingWindow)
877 wxMenubarSetInvokingWindow( menu, m_invokingWindow );
878
879 return TRUE;
880 }
881
882 static void wxMenubarUnsetInvokingWindow( wxMenu *menu )
883 {
884 menu->SetInvokingWindow( (wxWindow*) NULL );
885
886 wxMenuItemList::Node *node = menu->GetMenuItems().GetFirst();
887 while (node)
888 {
889 wxMenuItem *menuitem = node->GetData();
890 if (menuitem->IsSubMenu())
891 wxMenubarUnsetInvokingWindow( menuitem->GetSubMenu() );
892 node = node->GetNext();
893 }
894 }
895
896 static void wxMenubarSetInvokingWindow( wxMenu *menu, wxWindow *win )
897 {
898 menu->SetInvokingWindow( win );
899
900 wxMenuItemList::Node *node = menu->GetMenuItems().GetFirst();
901 while (node)
902 {
903 wxMenuItem *menuitem = node->GetData();
904 if (menuitem->IsSubMenu())
905 wxMenubarSetInvokingWindow( menuitem->GetSubMenu() , win );
906 node = node->GetNext();
907 }
908 }
909
910 void wxMenuBar::UnsetInvokingWindow()
911 {
912 m_invokingWindow = (wxWindow*) NULL;
913 wxMenuList::Node *node = m_menus.GetFirst();
914 while (node)
915 {
916 wxMenu *menu = node->GetData();
917 wxMenubarUnsetInvokingWindow( menu );
918 node = node->GetNext();
919 }
920 }
921
922 void wxMenuBar::SetInvokingWindow(wxFrame *frame)
923 {
924 m_invokingWindow = frame;
925 wxMenuList::Node *node = m_menus.GetFirst();
926 while (node)
927 {
928 wxMenu *menu = node->GetData();
929 wxMenubarSetInvokingWindow( menu, frame );
930 node = node->GetNext();
931 }
932 }
933
934 void wxMenuBar::Detach()
935 {
936 wxMenuBarBase::Detach() ;
937 }
938
939 void wxMenuBar::Attach(wxFrame *frame)
940 {
941 wxMenuBarBase::Attach( frame ) ;
942 }
943 // ---------------------------------------------------------------------------
944 // wxMenuBar searching for menu items
945 // ---------------------------------------------------------------------------
946
947 // Find the itemString in menuString, and return the item id or wxNOT_FOUND
948 int wxMenuBar::FindMenuItem(const wxString& menuString,
949 const wxString& itemString) const
950 {
951 wxString menuLabel = wxStripMenuCodes(menuString);
952 size_t count = GetMenuCount();
953 for ( size_t i = 0; i < count; i++ )
954 {
955 wxString title = wxStripMenuCodes(m_titles[i]);
956 if ( menuLabel == title )
957 return m_menus[i]->FindItem(itemString);
958 }
959
960 return wxNOT_FOUND;
961 }
962
963 wxMenuItem *wxMenuBar::FindItem(int id, wxMenu **itemMenu) const
964 {
965 if ( itemMenu )
966 *itemMenu = NULL;
967
968 wxMenuItem *item = NULL;
969 size_t count = GetMenuCount();
970 for ( size_t i = 0; !item && (i < count); i++ )
971 {
972 item = m_menus[i]->FindItem(id, itemMenu);
973 }
974
975 return item;
976 }
977
978