]> git.saurik.com Git - wxWidgets.git/blob - src/mac/carbon/menu.cpp
added test for env var expansion
[wxWidgets.git] / src / mac / carbon / menu.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: menu.cpp
3 // Purpose: wxMenu, wxMenuBar, wxMenuItem
4 // Author: AUTHOR
5 // Modified by:
6 // Created: ??/??/98
7 // RCS-ID: $Id$
8 // Copyright: (c) AUTHOR
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12
13 // ============================================================================
14 // headers & declarations
15 // ============================================================================
16
17 // wxWindows headers
18 // -----------------
19
20 #ifdef __GNUG__
21 #pragma implementation "menu.h"
22 #pragma implementation "menuitem.h"
23 #endif
24
25 #include "wx/app.h"
26 #include "wx/menu.h"
27 #include "wx/menuitem.h"
28 #include "wx/window.h"
29 #include "wx/log.h"
30 #include "wx/utils.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
54
55 // Menus
56
57 // Construct a menu with optional title (then use append)
58
59 #ifdef __DARWIN__
60 short wxMenu::s_macNextMenuId = 3 ;
61 #else
62 short wxMenu::s_macNextMenuId = 2 ;
63 #endif
64
65 void wxMenu::Init()
66 {
67 m_doBreak = FALSE;
68
69 // create the menu
70 Str255 label;
71 wxMenuItem::MacBuildMenuString( label, NULL , NULL , m_title , false );
72 m_macMenuId = s_macNextMenuId++;
73 m_hMenu = ::NewMenu(m_macMenuId, label);
74
75 if ( !m_hMenu )
76 {
77 wxLogLastError("CreatePopupMenu");
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 #if wxUSE_ACCEL
94 // delete accels
95 WX_CLEAR_ARRAY(m_accels);
96 #endif // wxUSE_ACCEL
97 }
98
99 void wxMenu::Break()
100 {
101 // not available on the mac platform
102 }
103
104 #if wxUSE_ACCEL
105
106 int wxMenu::FindAccel(int id) const
107 {
108 size_t n, count = m_accels.GetCount();
109 for ( n = 0; n < count; n++ )
110 {
111 if ( m_accels[n]->m_command == id )
112 return n;
113 }
114
115 return wxNOT_FOUND;
116 }
117
118 void wxMenu::UpdateAccel(wxMenuItem *item)
119 {
120 // find the (new) accel for this item
121 wxAcceleratorEntry *accel = wxGetAccelFromString(item->GetText());
122 if ( accel )
123 accel->m_command = item->GetId();
124
125 // find the old one
126 int n = FindAccel(item->GetId());
127 if ( n == wxNOT_FOUND )
128 {
129 // no old, add new if any
130 if ( accel )
131 m_accels.Add(accel);
132 else
133 return; // skipping RebuildAccelTable() below
134 }
135 else
136 {
137 // replace old with new or just remove the old one if no new
138 delete m_accels[n];
139 if ( accel )
140 m_accels[n] = accel;
141 else
142 m_accels.RemoveAt(n);
143 }
144
145 if ( IsAttached() )
146 {
147 m_menuBar->RebuildAccelTable();
148 }
149 }
150
151 #endif // wxUSE_ACCEL
152
153 // function appends a new item or submenu to the menu
154 // append a new item or submenu to the menu
155 bool wxMenu::DoInsertOrAppend(wxMenuItem *pItem, size_t pos)
156 {
157 wxASSERT_MSG( pItem != NULL, "can't append NULL item to the menu" );
158 #if wxUSE_ACCEL
159 UpdateAccel(pItem);
160 #endif // wxUSE_ACCEL
161
162 if ( pItem->IsSeparator() )
163 {
164 if ( pos == (size_t)-1 )
165 {
166 MacAppendMenu(MAC_WXHMENU(m_hMenu), "\p-");
167 }
168 else
169 {
170 MacInsertMenuItem(MAC_WXHMENU(m_hMenu), "\p-" , pos);
171 }
172 }
173 else
174 {
175 wxMenu *pSubMenu = pItem->GetSubMenu() ;
176 if ( pSubMenu != NULL )
177 {
178 Str255 label;
179 wxASSERT_MSG( pSubMenu->m_hMenu != NULL , "invalid submenu added");
180 pSubMenu->m_menuParent = this ;
181 wxMenuItem::MacBuildMenuString( label , NULL , NULL , pItem->GetText() ,false);
182
183 if (wxMenuBar::MacGetInstalledMenuBar() == m_menuBar)
184 {
185 ::InsertMenu( MAC_WXHMENU( pSubMenu->m_hMenu ) , -1 ) ;
186 }
187
188 if ( pos == (size_t)-1 )
189 {
190 UMAAppendSubMenuItem(MAC_WXHMENU(m_hMenu), label, pSubMenu->m_macMenuId);
191 }
192 else
193 {
194 UMAInsertSubMenuItem(MAC_WXHMENU(m_hMenu), label , pos, pSubMenu->m_macMenuId);
195 }
196 }
197 else
198 {
199 Str255 label ;
200 UInt8 modifiers ;
201 SInt16 key ;
202 wxMenuItem::MacBuildMenuString( label, &key , &modifiers , pItem->GetText(), pItem->GetId() == wxApp::s_macAboutMenuItemId);
203 if ( label[0] == 0 )
204 {
205 // we cannot add empty menus on mac
206 label[0] = 1 ;
207 label[1] = ' ' ;
208 }
209 if ( pos == (size_t)-1 )
210 {
211 UMAAppendMenuItem(MAC_WXHMENU(m_hMenu), label,key,modifiers);
212 if ( pItem->GetBitmap().Ok() )
213 {
214 ControlButtonContentInfo info ;
215 wxMacCreateBitmapButton( &info , pItem->GetBitmap() , true ) ;
216 if ( info.contentType != kControlNoContent )
217 {
218 if ( info.contentType == kControlContentCIconHandle )
219 SetMenuItemIconHandle( MAC_WXHMENU(m_hMenu) , CountMenuItems(MAC_WXHMENU(m_hMenu) ) ,
220 kMenuColorIconType , (Handle) info.u.cIconHandle ) ;
221 }
222
223 }
224 }
225 else
226 {
227 UMAInsertMenuItem(MAC_WXHMENU(m_hMenu), label , pos,key,modifiers);
228 if ( pItem->GetBitmap().Ok() )
229 {
230 ControlButtonContentInfo info ;
231 wxMacCreateBitmapButton( &info , pItem->GetBitmap() , true ) ;
232 if ( info.contentType != kControlNoContent )
233 {
234 if ( info.contentType == kControlContentCIconHandle )
235 SetMenuItemIconHandle( MAC_WXHMENU(m_hMenu) , pos ,
236 kMenuColorIconType , (Handle) info.u.cIconHandle ) ;
237 }
238
239 }
240 }
241 if ( pItem->GetId() == idMenuTitle )
242 {
243 if ( pos == (size_t)-1 )
244 {
245 UMADisableMenuItem(MAC_WXHMENU(m_hMenu) , CountMenuItems(MAC_WXHMENU(m_hMenu) ) ) ;
246 }
247 else
248 {
249 UMADisableMenuItem(MAC_WXHMENU(m_hMenu) , pos + 1 ) ;
250 }
251 }
252 }
253 }
254 // if we're already attached to the menubar, we must update it
255 if ( IsAttached() )
256 {
257 m_menuBar->Refresh();
258 }
259 return TRUE ;
260 }
261
262 bool wxMenu::DoAppend(wxMenuItem *item)
263 {
264 return wxMenuBase::DoAppend(item) && DoInsertOrAppend(item);
265 }
266
267 bool wxMenu::DoInsert(size_t pos, wxMenuItem *item)
268 {
269 return wxMenuBase::DoInsert(pos, item) && DoInsertOrAppend(item, pos);
270 }
271
272 wxMenuItem *wxMenu::DoRemove(wxMenuItem *item)
273 {
274 // we need to find the items position in the child list
275 size_t pos;
276 wxMenuItemList::Node *node = GetMenuItems().GetFirst();
277 for ( pos = 0; node; pos++ )
278 {
279 if ( node->GetData() == item )
280 break;
281
282 node = node->GetNext();
283 }
284
285 // DoRemove() (unlike Remove) can only be called for existing item!
286 wxCHECK_MSG( node, NULL, wxT("bug in wxMenu::Remove logic") );
287
288 #if wxUSE_ACCEL
289 // remove the corresponding accel from the accel table
290 int n = FindAccel(item->GetId());
291 if ( n != wxNOT_FOUND )
292 {
293 delete m_accels[n];
294
295 m_accels.RemoveAt(n);
296 }
297 //else: this item doesn't have an accel, nothing to do
298 #endif // wxUSE_ACCEL
299
300 ::DeleteMenuItem(MAC_WXHMENU(m_hMenu) , pos + 1);
301
302 if ( IsAttached() )
303 {
304 // otherwise, the chane won't be visible
305 m_menuBar->Refresh();
306 }
307
308 // and from internal data structures
309 return wxMenuBase::DoRemove(item);
310 }
311
312 // ---------------------------------------------------------------------------
313 // accelerator helpers
314 // ---------------------------------------------------------------------------
315
316 #if wxUSE_ACCEL
317
318 // create the wxAcceleratorEntries for our accels and put them into provided
319 // array - return the number of accels we have
320 size_t wxMenu::CopyAccels(wxAcceleratorEntry *accels) const
321 {
322 size_t count = GetAccelCount();
323 for ( size_t n = 0; n < count; n++ )
324 {
325 *accels++ = *m_accels[n];
326 }
327
328 return count;
329 }
330
331 #endif // wxUSE_ACCEL
332
333 void wxMenu::SetTitle(const wxString& label)
334 {
335 Str255 title ;
336 m_title = label ;
337 wxMenuItem::MacBuildMenuString( title, NULL , NULL , label , false );
338 UMASetMenuTitle(MAC_WXHMENU(m_hMenu) , title ) ;
339 }
340 bool wxMenu::ProcessCommand(wxCommandEvent & event)
341 {
342 bool processed = FALSE;
343
344 #if WXWIN_COMPATIBILITY
345 // Try a callback
346 if (m_callback)
347 {
348 (void)(*(m_callback))(*this, event);
349 processed = TRUE;
350 }
351 #endif WXWIN_COMPATIBILITY
352
353 // Try the menu's event handler
354 if ( !processed && GetEventHandler())
355 {
356 processed = GetEventHandler()->ProcessEvent(event);
357 }
358
359 // Try the window the menu was popped up from (and up through the
360 // hierarchy)
361 wxWindow *win = GetInvokingWindow();
362 if ( !processed && win )
363 processed = win->GetEventHandler()->ProcessEvent(event);
364
365 return processed;
366 }
367
368
369 // ---------------------------------------------------------------------------
370 // other
371 // ---------------------------------------------------------------------------
372
373 wxWindow *wxMenu::GetWindow() const
374 {
375 if ( m_invokingWindow != NULL )
376 return m_invokingWindow;
377 else if ( m_menuBar != NULL)
378 return (wxWindow *) m_menuBar->GetFrame();
379
380 return NULL;
381 }
382
383 // helper functions returning the mac menu position for a certain item, note that this is
384 // mac-wise 1 - based, i.e. the first item has index 1 whereas on MSWin it has pos 0
385
386 int wxMenu::MacGetIndexFromId( int id )
387 {
388 size_t pos;
389 wxMenuItemList::Node *node = GetMenuItems().GetFirst();
390 for ( pos = 0; node; pos++ )
391 {
392 if ( node->GetData()->GetId() == id )
393 break;
394
395 node = node->GetNext();
396 }
397
398 if (!node)
399 return 0;
400
401 return pos + 1 ;
402 }
403
404 int wxMenu::MacGetIndexFromItem( wxMenuItem *pItem )
405 {
406 size_t pos;
407 wxMenuItemList::Node *node = GetMenuItems().GetFirst();
408 for ( pos = 0; node; pos++ )
409 {
410 if ( node->GetData() == pItem )
411 break;
412
413 node = node->GetNext();
414 }
415
416 if (!node)
417 return 0;
418
419 return pos + 1 ;
420 }
421
422 void wxMenu::MacEnableMenu( bool bDoEnable )
423 {
424 if ( bDoEnable )
425 UMAEnableMenuItem(MAC_WXHMENU(m_hMenu) , 0 ) ;
426 else
427 UMADisableMenuItem(MAC_WXHMENU(m_hMenu) , 0 ) ;
428
429 ::DrawMenuBar() ;
430 }
431
432 bool wxMenu::MacMenuSelect( wxEvtHandler* handler, long when , int macMenuId, int macMenuItemNum )
433 {
434 int pos;
435 wxNode *node;
436
437 if ( m_macMenuId == macMenuId )
438 {
439 node = GetMenuItems().Nth(macMenuItemNum-1);
440 if (node)
441 {
442 wxMenuItem *pItem = (wxMenuItem*)node->Data();
443
444 if (pItem->IsCheckable())
445 pItem->Check(! pItem->IsChecked());
446
447 wxCommandEvent event(wxEVT_COMMAND_MENU_SELECTED, pItem->GetId());
448 event.m_timeStamp = when;
449 event.SetEventObject(handler);
450 event.SetInt( pItem->GetId() );
451 {
452 bool processed = false ;
453
454 #if WXWIN_COMPATIBILITY
455 // Try a callback
456 if (m_callback)
457 {
458 (void) (*(m_callback)) (*this, event);
459 processed = TRUE;
460 }
461 #endif
462 // Try the menu's event handler
463 if ( !processed && handler)
464 {
465 processed = handler->ProcessEvent(event);
466 }
467
468 // Try the window the menu was popped up from (and up
469 // through the hierarchy)
470 if ( !processed && GetInvokingWindow())
471 processed = GetInvokingWindow()->GetEventHandler()->ProcessEvent(event);
472 }
473 return true ;
474 }
475 }
476 else if ( macMenuId == kHMHelpMenuID )
477 {
478 int menuItem = firstUserHelpMenuItem-1 ;
479 for (pos = 0, node = GetMenuItems().First(); node; node = node->Next(), pos++)
480 {
481 wxMenuItem * pItem = (wxMenuItem *) node->Data() ;
482
483 wxMenu *pSubMenu = pItem->GetSubMenu() ;
484 if ( pSubMenu != NULL )
485 {
486 }
487 else
488 {
489 if ( pItem->GetId() != wxApp::s_macAboutMenuItemId )
490 ++menuItem ;
491
492 if ( menuItem == macMenuItemNum )
493 {
494 wxCommandEvent event(wxEVT_COMMAND_MENU_SELECTED, pItem->GetId());
495 event.m_timeStamp = when;
496 event.SetEventObject(handler);
497 event.SetInt( pItem->GetId() );
498 {
499 bool processed = false ;
500 #if WXWIN_COMPATIBILITY
501 // Try a callback
502 if (m_callback)
503 {
504 (void) (*(m_callback)) (*this, event);
505 processed = TRUE;
506 }
507 #endif
508 // Try the menu's event handler
509 if ( !processed && handler)
510 {
511 processed = handler->ProcessEvent(event);
512 }
513
514 // Try the window the menu was popped up from (and up
515 // through the hierarchy)
516 if ( !processed && GetInvokingWindow())
517 processed = GetInvokingWindow()->GetEventHandler()->ProcessEvent(event);
518 }
519 return true ;
520 }
521 }
522 }
523 }
524
525 for (pos = 0, node = GetMenuItems().First(); node; node = node->Next(), pos++)
526 {
527 wxMenuItem * pItem = (wxMenuItem *) node->Data() ;
528
529 wxMenu *pSubMenu = pItem->GetSubMenu() ;
530 if ( pSubMenu != NULL )
531 {
532 if ( pSubMenu->MacMenuSelect( handler , when , macMenuId , macMenuItemNum ) )
533 return true ;
534 }
535 }
536
537 return false ;
538 }
539
540 // Menu Bar
541
542 /*
543
544 Mac Implementation note :
545
546 The Mac has only one global menubar, so we attempt to install the currently
547 active menubar from a frame, we currently don't take into account mdi-frames
548 which would ask for menu-merging
549
550 Secondly there is no mac api for changing a menubar that is not the current
551 menubar, so we have to wait for preparing the actual menubar until the
552 wxMenubar is to be used
553
554 We can in subsequent versions use MacInstallMenuBar to provide some sort of
555 auto-merge for MDI in case this will be necessary
556
557 */
558
559 wxMenuBar* wxMenuBar::s_macInstalledMenuBar = NULL ;
560
561 void wxMenuBar::Init()
562 {
563 m_eventHandler = this;
564 m_menuBarFrame = NULL;
565 }
566
567 wxMenuBar::wxMenuBar()
568 {
569 Init();
570 }
571
572 wxMenuBar::wxMenuBar( long WXUNUSED(style) )
573 {
574 Init();
575 }
576
577
578 wxMenuBar::wxMenuBar(int count, wxMenu *menus[], const wxString titles[])
579 {
580 Init();
581
582 m_titles.Alloc(count);
583
584 for ( int i = 0; i < count; i++ )
585 {
586 m_menus.Append(menus[i]);
587 m_titles.Add(titles[i]);
588
589 menus[i]->Attach(this);
590 }
591 }
592
593 wxMenuBar::~wxMenuBar()
594 {
595 if (s_macInstalledMenuBar == this)
596 {
597 ::ClearMenuBar();
598 s_macInstalledMenuBar = NULL;
599 }
600
601 }
602
603 void wxMenuBar::Refresh(bool WXUNUSED(eraseBackground), const wxRect *WXUNUSED(rect))
604 {
605 wxCHECK_RET( IsAttached(), wxT("can't refresh unatteched menubar") );
606
607 DrawMenuBar();
608 }
609
610 #if wxUSE_ACCEL
611
612 void wxMenuBar::RebuildAccelTable()
613 {
614 // merge the accelerators of all menus into one accel table
615 size_t nAccelCount = 0;
616 size_t i, count = GetMenuCount();
617 for ( i = 0; i < count; i++ )
618 {
619 nAccelCount += m_menus[i]->GetAccelCount();
620 }
621
622 if ( nAccelCount )
623 {
624 wxAcceleratorEntry *accelEntries = new wxAcceleratorEntry[nAccelCount];
625
626 nAccelCount = 0;
627 for ( i = 0; i < count; i++ )
628 {
629 nAccelCount += m_menus[i]->CopyAccels(&accelEntries[nAccelCount]);
630 }
631
632 m_accelTable = wxAcceleratorTable(nAccelCount, accelEntries);
633
634 delete [] accelEntries;
635 }
636 }
637
638 #endif // wxUSE_ACCEL
639
640 void wxMenuBar::MacInstallMenuBar()
641 {
642 if ( s_macInstalledMenuBar == this )
643 return ;
644
645 wxStAppResource resload ;
646
647 Handle menubar = ::GetNewMBar( kwxMacMenuBarResource ) ;
648 wxString message ;
649 wxCHECK_RET( menubar != NULL, "can't read MBAR resource" );
650 ::SetMenuBar( menubar ) ;
651 #if TARGET_API_MAC_CARBON
652 ::DisposeMenuBar( menubar ) ;
653 #else
654 ::DisposeHandle( menubar ) ;
655 #endif
656
657 #if TARGET_API_MAC_OS8
658 MenuHandle menu = ::GetMenuHandle( kwxMacAppleMenuId ) ;
659 if ( CountMenuItems( menu ) == 2 )
660 {
661 ::AppendResMenu(menu, 'DRVR');
662 }
663 #endif
664
665 for (size_t i = 0; i < m_menus.GetCount(); i++)
666 {
667 Str255 label;
668 wxNode *node;
669 wxMenuItem *item;
670 int pos ;
671 wxMenu* menu = m_menus[i] , *subMenu = NULL ;
672
673 if( m_titles[i] == "?" || m_titles[i] == "&?" || m_titles[i] == wxApp::s_macHelpMenuTitleName )
674 {
675 MenuHandle mh = NULL ;
676 if ( UMAGetHelpMenu( &mh , &firstUserHelpMenuItem) != noErr )
677 {
678 continue ;
679 }
680
681 for ( int i = CountMenuItems( mh ) ; i >= firstUserHelpMenuItem ; --i )
682 {
683 DeleteMenuItem( mh , i ) ;
684 }
685
686 for (pos = 0 , node = menu->GetMenuItems().First(); node; node = node->Next(), pos++)
687 {
688 item = (wxMenuItem *)node->Data();
689 subMenu = item->GetSubMenu() ;
690 if (subMenu)
691 {
692 // we don't support hierarchical menus in the help menu yet
693 }
694 else
695 {
696 if ( item->IsSeparator() )
697 {
698 if ( mh )
699 MacAppendMenu(mh, "\p-" );
700 }
701 else
702 {
703 Str255 label ;
704 UInt8 modifiers ;
705 SInt16 key ;
706 wxMenuItem::MacBuildMenuString( label, &key , &modifiers , item->GetText(), item->GetId() != wxApp::s_macAboutMenuItemId); // no shortcut in about menu
707 if ( label[0] == 0 )
708 {
709 // we cannot add empty menus on mac
710 label[0] = 1 ;
711 label[1] = ' ' ;
712 }
713 if ( item->GetId() == wxApp::s_macAboutMenuItemId )
714 {
715 ::SetMenuItemText( GetMenuHandle( kwxMacAppleMenuId ) , 1 , label );
716 UMAEnableMenuItem( GetMenuHandle( kwxMacAppleMenuId ) , 1 );
717 }
718 else
719 {
720 if ( mh )
721 UMAAppendMenuItem(mh, label , key , modifiers );
722 }
723 }
724 }
725 }
726 }
727 else
728 {
729 wxMenuItem::MacBuildMenuString( label, NULL , NULL , m_titles[i] , false );
730 UMASetMenuTitle( MAC_WXHMENU(menu->GetHMenu()) , label ) ;
731 wxArrayPtrVoid submenus ;
732
733 for (pos = 0, node = menu->GetMenuItems().First(); node; node = node->Next(), pos++)
734 {
735 item = (wxMenuItem *)node->Data();
736 subMenu = item->GetSubMenu() ;
737 if (subMenu)
738 {
739 submenus.Add(subMenu) ;
740 }
741 }
742 ::InsertMenu(MAC_WXHMENU(m_menus[i]->GetHMenu()), 0);
743 for ( size_t i = 0 ; i < submenus.GetCount() ; ++i )
744 {
745 wxMenu* submenu = (wxMenu*) submenus[i] ;
746 wxNode *subnode;
747 wxMenuItem *subitem;
748 int subpos ;
749 for ( subpos = 0 , subnode = submenu->GetMenuItems().First(); subnode; subnode = subnode->Next(), subpos++)
750 {
751 subitem = (wxMenuItem *)subnode->Data();
752 wxMenu* itsSubMenu = subitem->GetSubMenu() ;
753 if (itsSubMenu)
754 {
755 submenus.Add(itsSubMenu) ;
756 }
757 }
758 ::InsertMenu( MAC_WXHMENU(submenu->GetHMenu()) , -1 ) ;
759 }
760 }
761 }
762 ::DrawMenuBar() ;
763 s_macInstalledMenuBar = this;
764 }
765
766 void wxMenuBar::EnableTop(size_t pos, bool enable)
767 {
768 wxCHECK_RET( IsAttached(), wxT("doesn't work with unattached menubars") );
769 m_menus[pos]->MacEnableMenu( enable ) ;
770 Refresh();
771 }
772
773 void wxMenuBar::SetLabelTop(size_t pos, const wxString& label)
774 {
775 wxCHECK_RET( pos < GetMenuCount(), wxT("invalid menu index") );
776
777 m_titles[pos] = label;
778
779 if ( !IsAttached() )
780 {
781 return;
782 }
783
784 m_menus[pos]->SetTitle( label ) ;
785 if (wxMenuBar::s_macInstalledMenuBar == this) // are we currently installed ?
786 {
787 ::SetMenuBar( GetMenuBar() ) ;
788 ::InvalMenuBar() ;
789 }
790 }
791
792 wxString wxMenuBar::GetLabelTop(size_t pos) const
793 {
794 wxCHECK_MSG( pos < GetMenuCount(), wxEmptyString,
795 wxT("invalid menu index in wxMenuBar::GetLabelTop") );
796
797 return m_titles[pos];
798 }
799
800 int wxMenuBar::FindMenu(const wxString& title)
801 {
802 wxString menuTitle = wxStripMenuCodes(title);
803
804 size_t count = GetMenuCount();
805 for ( size_t i = 0; i < count; i++ )
806 {
807 wxString title = wxStripMenuCodes(m_titles[i]);
808 if ( menuTitle == title )
809 return i;
810 }
811
812 return wxNOT_FOUND;
813
814 }
815
816
817 // ---------------------------------------------------------------------------
818 // wxMenuBar construction
819 // ---------------------------------------------------------------------------
820
821 // ---------------------------------------------------------------------------
822 // wxMenuBar construction
823 // ---------------------------------------------------------------------------
824
825 wxMenu *wxMenuBar::Replace(size_t pos, wxMenu *menu, const wxString& title)
826 {
827 wxMenu *menuOld = wxMenuBarBase::Replace(pos, menu, title);
828 if ( !menuOld )
829 return FALSE;
830 m_titles[pos] = title;
831
832 if ( IsAttached() )
833 {
834 if (s_macInstalledMenuBar == this)
835 {
836 ::DeleteMenu( menuOld->MacGetMenuId() /* m_menus[pos]->MacGetMenuId() */ ) ;
837 {
838 Str255 label;
839 wxMenuItem::MacBuildMenuString( label, NULL , NULL , title , false );
840 UMASetMenuTitle( MAC_WXHMENU(menu->GetHMenu()) , label ) ;
841 if ( pos == m_menus.GetCount() - 1)
842 {
843 ::InsertMenu( MAC_WXHMENU(menu->GetHMenu()) , 0 ) ;
844 }
845 else
846 {
847 ::InsertMenu( MAC_WXHMENU(menu->GetHMenu()) , m_menus[pos+1]->MacGetMenuId() ) ;
848 }
849 }
850 }
851
852
853 #if wxUSE_ACCEL
854 if ( menuOld->HasAccels() || menu->HasAccels() )
855 {
856 // need to rebuild accell table
857 RebuildAccelTable();
858 }
859 #endif // wxUSE_ACCEL
860
861 Refresh();
862 }
863
864 return menuOld;
865 }
866
867 bool wxMenuBar::Insert(size_t pos, wxMenu *menu, const wxString& title)
868 {
869 if ( !wxMenuBarBase::Insert(pos, menu, title) )
870 return FALSE;
871
872 m_titles.Insert(title, pos);
873
874 Str255 label ;
875 wxMenuItem::MacBuildMenuString( label, NULL , NULL , title , false );
876 UMASetMenuTitle( MAC_WXHMENU(menu->GetHMenu()) , label ) ;
877
878 if ( IsAttached() )
879 {
880 if ( pos == (size_t) -1 || pos + 1 == m_menus.GetCount() )
881 {
882 ::InsertMenu( MAC_WXHMENU(menu->GetHMenu()) , 0 ) ;
883 }
884 else
885 {
886 ::InsertMenu( MAC_WXHMENU(menu->GetHMenu()) , m_menus[pos+1]->MacGetMenuId() ) ;
887 }
888
889 #if wxUSE_ACCEL
890 if ( menu->HasAccels() )
891 {
892 // need to rebuild accell table
893 RebuildAccelTable();
894 }
895 #endif // wxUSE_ACCEL
896
897 Refresh();
898 }
899
900 return TRUE;
901 }
902
903 void wxMenuBar::MacMenuSelect(wxEvtHandler* handler, long when , int macMenuId, int macMenuItemNum)
904 {
905 // first scan fast for direct commands, i.e. menus which have these commands directly in their own list
906
907 if ( macMenuId == kwxMacAppleMenuId && macMenuItemNum == 1 )
908 {
909 wxCommandEvent event(wxEVT_COMMAND_MENU_SELECTED, wxApp::s_macAboutMenuItemId );
910 event.m_timeStamp = when;
911 event.SetEventObject(handler);
912 event.SetInt( wxApp::s_macAboutMenuItemId );
913 handler->ProcessEvent(event);
914 }
915 else
916 {
917 for (size_t i = 0; i < m_menus.GetCount() ; i++)
918 {
919 if ( m_menus[i]->MacGetMenuId() == macMenuId || ( macMenuId == kHMHelpMenuID && ( m_titles[i] == "?" || m_titles[i] == "&?" || m_titles[i] == wxApp::s_macHelpMenuTitleName ) ) )
920 {
921 if ( m_menus[i]->MacMenuSelect( handler , when , macMenuId , macMenuItemNum ) )
922 return ;
923 else
924 {
925 //TODO flag this as an error since it must contain the item
926 return ;
927 }
928 }
929 }
930
931 for (size_t i = 0; i < m_menus.GetCount(); i++)
932 {
933 if ( m_menus[i]->MacMenuSelect( handler , when , macMenuId , macMenuItemNum ) )
934 {
935 break ;
936 }
937 }
938 }
939 }
940
941 wxMenu *wxMenuBar::Remove(size_t pos)
942 {
943 wxMenu *menu = wxMenuBarBase::Remove(pos);
944 if ( !menu )
945 return NULL;
946
947 if ( IsAttached() )
948 {
949 if (s_macInstalledMenuBar == this)
950 {
951 ::DeleteMenu( menu->MacGetMenuId() /* m_menus[pos]->MacGetMenuId() */ ) ;
952 }
953
954 menu->Detach();
955
956 #if wxUSE_ACCEL
957 if ( menu->HasAccels() )
958 {
959 // need to rebuild accell table
960 RebuildAccelTable();
961 }
962 #endif // wxUSE_ACCEL
963
964 Refresh();
965 }
966
967 m_titles.Remove(pos);
968
969 return menu;
970 }
971
972 bool wxMenuBar::Append(wxMenu *menu, const wxString& title)
973 {
974 WXHMENU submenu = menu ? menu->GetHMenu() : 0;
975 wxCHECK_MSG( submenu, FALSE, wxT("can't append invalid menu to menubar") );
976
977 if ( !wxMenuBarBase::Append(menu, title) )
978 return FALSE;
979
980 m_titles.Add(title);
981
982 Str255 label ;
983 wxMenuItem::MacBuildMenuString( label, NULL , NULL , title , false );
984 UMASetMenuTitle( MAC_WXHMENU(menu->GetHMenu()) , label ) ;
985
986 if ( IsAttached() )
987 {
988 if (s_macInstalledMenuBar == this)
989 {
990 ::InsertMenu( MAC_WXHMENU(menu->GetHMenu()) , 0 ) ;
991 }
992
993 #if wxUSE_ACCEL
994 if ( menu->HasAccels() )
995 {
996 // need to rebuild accell table
997 RebuildAccelTable();
998 }
999 #endif // wxUSE_ACCEL
1000
1001 Refresh();
1002 }
1003
1004 return TRUE;
1005 }
1006
1007 void wxMenuBar::Detach()
1008 {
1009 wxMenuBarBase::Detach() ;
1010 }
1011
1012 void wxMenuBar::Attach(wxFrame *frame)
1013 {
1014 wxMenuBarBase::Attach( frame ) ;
1015
1016 #if wxUSE_ACCEL
1017 RebuildAccelTable();
1018 #endif // wxUSE_ACCEL
1019 }
1020 // ---------------------------------------------------------------------------
1021 // wxMenuBar searching for menu items
1022 // ---------------------------------------------------------------------------
1023
1024 // Find the itemString in menuString, and return the item id or wxNOT_FOUND
1025 int wxMenuBar::FindMenuItem(const wxString& menuString,
1026 const wxString& itemString) const
1027 {
1028 wxString menuLabel = wxStripMenuCodes(menuString);
1029 size_t count = GetMenuCount();
1030 for ( size_t i = 0; i < count; i++ )
1031 {
1032 wxString title = wxStripMenuCodes(m_titles[i]);
1033 if ( menuString == title )
1034 return m_menus[i]->FindItem(itemString);
1035 }
1036
1037 return wxNOT_FOUND;
1038 }
1039
1040 wxMenuItem *wxMenuBar::FindItem(int id, wxMenu **itemMenu) const
1041 {
1042 if ( itemMenu )
1043 *itemMenu = NULL;
1044
1045 wxMenuItem *item = NULL;
1046 size_t count = GetMenuCount();
1047 for ( size_t i = 0; !item && (i < count); i++ )
1048 {
1049 item = m_menus[i]->FindItem(id, itemMenu);
1050 }
1051
1052 return item;
1053 }
1054
1055