]> git.saurik.com Git - wxWidgets.git/blob - src/mac/menu.cpp
fixed menu accelerators
[wxWidgets.git] / src / mac / 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/menu.h"
26 #include "wx/menuitem.h"
27 #include "wx/log.h"
28 #include "wx/utils.h"
29
30 #include "wx/mac/uma.h"
31
32 // other standard headers
33 // ----------------------
34 #include <string.h>
35
36 #if !USE_SHARED_LIBRARY
37 IMPLEMENT_DYNAMIC_CLASS(wxMenu, wxEvtHandler)
38 IMPLEMENT_DYNAMIC_CLASS(wxMenuBar, wxEvtHandler)
39 #endif
40
41 // the (popup) menu title has this special id
42 static const int idMenuTitle = -2;
43 static int formerHelpMenuItems = 0 ;
44
45 const short kwxMacMenuBarResource = 1 ;
46 const short kwxMacAppleMenuId = 1 ;
47
48 // ============================================================================
49 // implementation
50 // ============================================================================
51
52 //
53 // Helper Functions to get Mac Menus the way they should be ;-)
54 //
55
56 void wxMacCtoPString(const char* theCString, Str255 thePString);
57
58 // remove inappropriate characters, if useShortcuts is false, the ampersand will not auto-generate a mac menu-shortcut
59
60 static void wxMacBuildMenuString(StringPtr outMacItemText, char *outMacShortcutChar , short *outMacModifiers , const char *inItemName , bool useShortcuts )
61 {
62 char *p = (char *) &outMacItemText[1] ;
63 short macModifiers = 0 ;
64 char macShortCut = 0 ;
65
66 if ( useShortcuts && !wxApp::s_macSupportPCMenuShortcuts )
67 useShortcuts = false ;
68
69 // we have problems with a leading hypen - it will be taken as a separator
70
71 while ( *inItemName == '-' )
72 inItemName++ ;
73
74 while( *inItemName )
75 {
76 switch ( *inItemName )
77 {
78 // special characters for macintosh menus -> use some replacement
79 case ';' :
80 *p++ = ',' ;
81 break ;
82 case '^' :
83 *p++ = ' ' ;
84 break ;
85 case '!' :
86 *p++ = ' ' ;
87 break ;
88 case '<' :
89 *p++ = ' ' ;
90 break ;
91 case '/' :
92 *p++ = '|' ;
93 break ;
94 case '(' :
95 *p++ = '[' ;
96 break ;
97 case ')' :
98 *p++ = ']' ;
99 break ;
100 // shortcuts
101 case '&' :
102 {
103 ++inItemName ;
104 if ( *inItemName )
105 {
106 *p++ = *inItemName ;
107 if ( useShortcuts )
108 macShortCut = *inItemName ;
109 }
110 else
111 --inItemName ;
112 }
113 break ;
114 // win-like accelerators
115 case '\t' :
116 {
117 ++inItemName ;
118 while( *inItemName )
119 {
120 if (strncmp("Ctrl+", inItemName, 5) == 0)
121 {
122 inItemName = inItemName + 5;
123 macShortCut = *inItemName;
124 }
125 else if (strncmp("Alt+", inItemName, 4) == 0)
126 {
127 inItemName = inItemName + 4;
128 macModifiers |= kMenuOptionModifier ;
129 macShortCut = *inItemName ;
130 }
131 else if (strncmp("Shift+", inItemName, 6) == 0)
132 {
133 inItemName = inItemName + 6;
134 macModifiers |= kMenuShiftModifier ;
135 macShortCut = *inItemName ;
136 }
137 else if (strncmp("F", inItemName, 1) == 0)
138 {
139 inItemName += strlen( inItemName ) ;
140 // no function keys at the moment
141 // macModifiers |= kMenuShiftModifier ;
142 // macShortCut = *inItemName ;
143 }
144 else
145 {
146 break ;
147 }
148 }
149
150 if ( *inItemName == 0 )
151 --inItemName ;
152
153 }
154 break ;
155 default :
156 *p++ = *inItemName ;
157 }
158 ++inItemName ;
159 }
160
161 outMacItemText[0] = (p - (char *)outMacItemText) - 1;
162 if ( outMacShortcutChar )
163 *outMacShortcutChar = macShortCut ;
164 if ( outMacModifiers )
165 *outMacModifiers = macModifiers ;
166 if ( macShortCut )
167 {
168 int pos = outMacItemText[0] ;
169 outMacItemText[++pos] = '/';
170 outMacItemText[++pos] = toupper( macShortCut );
171 outMacItemText[0] = pos ;
172 }
173 }
174
175 // Menus
176
177 // Construct a menu with optional title (then use append)
178
179 short wxMenu::s_macNextMenuId = 2 ;
180
181 wxMenu::wxMenu(const wxString& title, const wxFunction func)
182 {
183 m_title = title;
184 m_parent = NULL;
185 m_eventHandler = this;
186 m_noItems = 0;
187 m_menuBar = NULL;
188 m_pInvokingWindow = NULL ;
189 m_clientData = (void*) NULL;
190 if (m_title != "")
191 {
192 Append(idMenuTitle, m_title) ;
193 AppendSeparator() ;
194 }
195
196 Callback(func);
197
198 Str255 label;
199 wxMacBuildMenuString( label, NULL , NULL , title , false );
200 m_macMenuId = s_macNextMenuId++;
201 wxCHECK_RET( s_macNextMenuId < 236 , "menu ids > 235 cannot be used for submenus on mac" );
202 m_macMenuHandle = ::NewMenu(m_macMenuId, label);
203 m_macMenuEnabled = true ;
204 }
205
206 // The wxWindow destructor will take care of deleting the submenus.
207 wxMenu::~wxMenu()
208 {
209 wxNode *node = m_menuItems.First();
210 while (node)
211 {
212 wxMenuItem *item = (wxMenuItem *)node->Data();
213
214 // Delete child menus.
215 // Beware: they must not be appended to children list!!!
216 // (because order of delete is significant)
217 if (item->GetSubMenu())
218 item->DeleteSubMenu();
219
220 wxNode *next = node->Next();
221 delete item;
222 delete node;
223 node = next;
224 }
225 if (m_macMenuHandle)
226 ::DisposeMenu(m_macMenuHandle);
227 }
228
229 void wxMenu::Break()
230 {
231 // not available on the mac platform
232 }
233
234 // function appends a new item or submenu to the menu
235 void wxMenu::Append(wxMenuItem *pItem)
236 {
237 wxCHECK_RET( pItem != NULL, "can't append NULL item to the menu" );
238
239 m_menuItems.Append(pItem);
240
241 if ( pItem->IsSeparator() )
242 {
243 MacAppendMenu(m_macMenuHandle, "\p-");
244 }
245 else
246 {
247 wxMenu *pSubMenu = pItem->GetSubMenu() ;
248 if ( pSubMenu != NULL )
249 {
250 Str255 label;
251 wxCHECK_RET( pSubMenu->m_macMenuHandle != NULL , "invalid submenu added");
252 pSubMenu->m_parent = this ;
253 wxMacBuildMenuString( label , NULL , NULL , pItem->GetName() ,false);
254
255 // hardcoded adding of the submenu combination for mac
256
257 int theEnd = label[0] + 1;
258 if (theEnd > 251)
259 theEnd = 251; // mac allows only 255 characters
260 label[theEnd++] = '/';
261 label[theEnd++] = hMenuCmd;
262 label[theEnd++] = '!';
263 label[theEnd++] = pSubMenu->m_macMenuId;
264 label[theEnd] = 0x00;
265 label[0] = theEnd;
266
267 if (wxMenuBar::s_macInstalledMenuBar == m_menuBar)
268 {
269 ::InsertMenu( pSubMenu->m_macMenuHandle , -1 ) ;
270 }
271
272 ::AppendMenu(m_macMenuHandle, label);
273 }
274 else
275 {
276 Str255 label ;
277 wxMacBuildMenuString( label , NULL , NULL , pItem->GetName(), pItem->GetId() == wxApp::s_macAboutMenuItemId);
278 if ( label[0] == 0 )
279 {
280 // we cannot add empty menus on mac
281 label[0] = 1 ;
282 label[1] = ' ' ;
283 }
284 ::AppendMenu(m_macMenuHandle, label );
285 if ( pItem->GetId() == idMenuTitle )
286 {
287 UMADisableMenuItem( m_macMenuHandle , CountMItems( m_macMenuHandle ) ) ;
288 }
289 }
290 }
291
292 m_noItems++;
293 }
294
295 void wxMenu::AppendSeparator()
296 {
297 Append(new wxMenuItem(this, ID_SEPARATOR));
298 }
299
300 // Pullright item
301 void wxMenu::Append(int Id, const wxString& label, wxMenu *SubMenu,
302 const wxString& helpString)
303 {
304 Append(new wxMenuItem(this, Id, label, helpString, FALSE, SubMenu));
305 }
306
307 // Ordinary menu item
308 void wxMenu::Append(int Id, const wxString& label,
309 const wxString& helpString, bool checkable)
310 {
311 // 'checkable' parameter is useless for Windows.
312 Append(new wxMenuItem(this, Id, label, helpString, checkable));
313 }
314
315 void wxMenu::Delete(int id)
316 {
317 wxNode *node;
318 wxMenuItem *item;
319 int pos;
320
321 for (pos = 0, node = m_menuItems.First(); node; node = node->Next(), pos++) {
322 item = (wxMenuItem *)node->Data();
323 if (item->GetId() == id)
324 break;
325 }
326
327 if (!node)
328 return;
329
330 int index = pos + 1 ;
331
332 if (index < 1)
333 return;
334
335 wxMenu *pSubMenu = item->GetSubMenu();
336 if ( pSubMenu != NULL )
337 {
338 ::DeleteMenuItem( m_macMenuHandle , index);
339 pSubMenu->m_parent = NULL;
340 // TODO: Why isn't subMenu deleted here???
341 // Will put this in for now. Assuming this is supposed
342 // to delete the menu, not just remove it.
343 item->DeleteSubMenu();
344 }
345 else
346 {
347 ::DeleteMenuItem( m_macMenuHandle , index);
348 }
349
350 m_menuItems.DeleteNode(node);
351 // TODO shouldn't we do this ? \8e_m_noItems--;
352 delete item;
353 }
354
355 void wxMenu::Enable(int Id, bool Flag)
356 {
357 wxMenuItem *item = FindItemForId(Id);
358 wxCHECK_RET( item != NULL, "can't enable non-existing menu item" );
359
360 item->Enable(Flag);
361 }
362
363 bool wxMenu::Enabled(int Id) const
364 {
365 wxMenuItem *item = FindItemForId(Id);
366 wxCHECK( item != NULL, FALSE );
367
368 return item->IsEnabled();
369 }
370
371 void wxMenu::Check(int Id, bool Flag)
372 {
373 wxMenuItem *item = FindItemForId(Id);
374 wxCHECK_RET( item != NULL, "can't get status of non-existing menu item" );
375
376 item->Check(Flag);
377 }
378
379 bool wxMenu::Checked(int Id) const
380 {
381 wxMenuItem *item = FindItemForId(Id);
382 wxCHECK( item != NULL, FALSE );
383
384 return item->IsChecked();
385 }
386
387 void wxMenu::SetTitle(const wxString& label)
388 {
389 Str255 title ;
390 m_title = label ;
391 wxMacBuildMenuString( title, NULL , NULL , label , false );
392 UMASetMenuTitle( m_macMenuHandle , title ) ;
393 if (wxMenuBar::s_macInstalledMenuBar == m_menuBar) // are we currently installed ?
394 {
395 ::SetMenuBar( GetMenuBar() ) ;
396 ::InvalMenuBar() ;
397 }
398 // TODO:for submenus -> their parent item text must be corrected
399 }
400
401 const wxString wxMenu::GetTitle() const
402 {
403 return m_title;
404 }
405
406 void wxMenu::SetLabel(int id, const wxString& label)
407 {
408 Str255 maclabel ;
409 int index ;
410 wxMenuItem *item = FindItemForId(id) ;
411 if (item==NULL)
412 return;
413
414 index = MacGetIndexFromItem( item ) ;
415 if (index < 1)
416 return;
417
418 if (item->GetSubMenu()==NULL)
419 {
420 wxMacBuildMenuString( maclabel , NULL , NULL , label , false );
421 ::SetMenuItemText( m_macMenuHandle , index , maclabel ) ;
422 }
423 else
424 {
425 wxMacBuildMenuString( maclabel , NULL , NULL , label , false );
426 ::SetMenuItemText( m_macMenuHandle , index , maclabel ) ;
427 }
428 item->SetName(label);
429 }
430
431 wxString wxMenu::GetLabel(int Id) const
432 {
433 wxMenuItem *pItem = FindItemForId(Id) ;
434 return pItem->GetName() ;
435 }
436
437 // Finds the item id matching the given string, -1 if not found.
438 int wxMenu::FindItem (const wxString& itemString) const
439 {
440 char buf1[200];
441 char buf2[200];
442 wxStripMenuCodes ((char *)(const char *)itemString, buf1);
443
444 for (wxNode * node = m_menuItems.First (); node; node = node->Next ())
445 {
446 wxMenuItem *item = (wxMenuItem *) node->Data ();
447 if (item->GetSubMenu())
448 {
449 int ans = item->GetSubMenu()->FindItem(itemString);
450 if (ans > -1)
451 return ans;
452 }
453 if ( !item->IsSeparator() )
454 {
455 wxStripMenuCodes((char *)item->GetName().c_str(), buf2);
456 if (strcmp(buf1, buf2) == 0)
457 return item->GetId();
458 }
459 }
460
461 return -1;
462 }
463
464 wxMenuItem *wxMenu::FindItemForId(int itemId, wxMenu ** itemMenu) const
465 {
466 if (itemMenu)
467 *itemMenu = NULL;
468 for (wxNode * node = m_menuItems.First (); node; node = node->Next ())
469 {
470 wxMenuItem *item = (wxMenuItem *) node->Data ();
471
472 if (item->GetId() == itemId)
473 {
474 if (itemMenu)
475 *itemMenu = (wxMenu *) this;
476 return item;
477 }
478
479 if (item->GetSubMenu())
480 {
481 wxMenuItem *ans = item->GetSubMenu()->FindItemForId (itemId, itemMenu);
482 if (ans)
483 return ans;
484 }
485 }
486
487 if (itemMenu)
488 *itemMenu = NULL;
489 return NULL;
490 }
491
492 void wxMenu::SetHelpString(int itemId, const wxString& helpString)
493 {
494 wxMenuItem *item = FindItemForId (itemId);
495 if (item)
496 item->SetHelp(helpString);
497 }
498
499 wxString wxMenu::GetHelpString (int itemId) const
500 {
501 wxMenuItem *item = FindItemForId (itemId);
502 wxString str("");
503 return (item == NULL) ? str : item->GetHelp();
504 }
505
506 void wxMenu::ProcessCommand(wxCommandEvent & event)
507 {
508 bool processed = FALSE;
509
510 // Try a callback
511 if (m_callback)
512 {
513 (void) (*(m_callback)) (*this, event);
514 processed = TRUE;
515 }
516
517 // Try the menu's event handler
518 if ( !processed && GetEventHandler())
519 {
520 processed = GetEventHandler()->ProcessEvent(event);
521 }
522
523 // Try the window the menu was popped up from (and up
524 // through the hierarchy)
525 if ( !processed && GetInvokingWindow())
526 processed = GetInvokingWindow()->GetEventHandler()->ProcessEvent(event);
527 }
528
529 bool wxWindow::PopupMenu(wxMenu *menu, int x, int y)
530 {
531 menu->SetInvokingWindow(this);
532 ClientToScreen( &x , &y ) ;
533
534 ::InsertMenu( menu->m_macMenuHandle , -1 ) ;
535 long menuResult = ::PopUpMenuSelect(menu->m_macMenuHandle ,y,x, 0) ;
536 menu->MacMenuSelect( this , TickCount() , HiWord(menuResult) , LoWord(menuResult) ) ;
537 ::DeleteMenu( menu->m_macMenuId ) ;
538 menu->SetInvokingWindow(NULL);
539
540 return TRUE;
541 }
542
543 // helper functions returning the mac menu position for a certain item, note that this is
544 // mac-wise 1 - based, i.e. the first item has index 1 whereas on MSWin it has pos 0
545
546 int wxMenu::MacGetIndexFromId( int id )
547 {
548 wxNode *node;
549 wxMenuItem *item;
550 int pos;
551
552 for (pos = 0, node = m_menuItems.First(); node; node = node->Next(), pos++)
553 {
554 item = (wxMenuItem *)node->Data();
555 if (item->GetId() == id)
556 break;
557 }
558
559 if (!node)
560 return 0;
561
562 return pos + 1 ;
563 }
564
565 int wxMenu::MacGetIndexFromItem( wxMenuItem *pItem )
566 {
567 wxNode *node;
568 int pos;
569
570 for (pos = 0, node = m_menuItems.First(); node; node = node->Next(), pos++)
571 {
572 if ((wxMenuItem *)node->Data() == pItem)
573 break;
574 }
575
576 if (!node)
577 return 0;
578
579 return pos + 1 ;
580 }
581
582 void wxMenu::MacEnableMenu( bool bDoEnable )
583 {
584 m_macMenuEnabled = bDoEnable ;
585 if ( bDoEnable )
586 UMAEnableMenuItem( m_macMenuHandle , 0 ) ;
587 else
588 UMADisableMenuItem( m_macMenuHandle , 0 ) ;
589
590 ::DrawMenuBar() ;
591 }
592
593 bool wxMenu::MacMenuSelect( wxEvtHandler* handler, long when , int macMenuId, int macMenuItemNum )
594 {
595 int pos;
596 wxNode *node;
597
598 if ( m_macMenuId == macMenuId )
599 {
600 node = m_menuItems.Nth(macMenuItemNum-1);
601 if (node)
602 {
603 wxMenuItem *pItem = (wxMenuItem*)node->Data();
604
605 wxCommandEvent event(wxEVT_COMMAND_MENU_SELECTED, pItem->GetId());
606 event.m_timeStamp = when;
607 event.SetEventObject(handler);
608 event.SetInt( pItem->GetId() );
609
610 {
611 bool processed = false ;
612
613 // Try a callback
614 if (m_callback)
615 {
616 (void) (*(m_callback)) (*this, event);
617 processed = TRUE;
618 }
619
620 // Try the menu's event handler
621 if ( !processed && handler)
622 {
623 processed = handler->ProcessEvent(event);
624 }
625
626 // Try the window the menu was popped up from (and up
627 // through the hierarchy)
628 if ( !processed && GetInvokingWindow())
629 processed = GetInvokingWindow()->GetEventHandler()->ProcessEvent(event);
630 }
631 return true ;
632 }
633 }
634 else if ( macMenuId == kHMHelpMenuID )
635 {
636 int menuItem = formerHelpMenuItems ;
637 for (pos = 0, node = m_menuItems.First(); node; node = node->Next(), pos++)
638 {
639 wxMenuItem * pItem = (wxMenuItem *) node->Data() ;
640
641 wxMenu *pSubMenu = pItem->GetSubMenu() ;
642 if ( pSubMenu != NULL )
643 {
644 }
645 else
646 {
647 if ( pItem->GetId() != wxApp::s_macAboutMenuItemId )
648 ++menuItem ;
649
650 if ( menuItem == macMenuItemNum )
651 {
652 wxCommandEvent event(wxEVT_COMMAND_MENU_SELECTED, pItem->GetId());
653 event.m_timeStamp = when;
654 event.SetEventObject(handler);
655 event.SetInt( pItem->GetId() );
656
657 {
658 bool processed = false ;
659 // Try a callback
660 if (m_callback)
661 {
662 (void) (*(m_callback)) (*this, event);
663 processed = TRUE;
664 }
665
666 // Try the menu's event handler
667 if ( !processed && handler)
668 {
669 processed = handler->ProcessEvent(event);
670 }
671
672 // Try the window the menu was popped up from (and up
673 // through the hierarchy)
674 if ( !processed && GetInvokingWindow())
675 processed = GetInvokingWindow()->GetEventHandler()->ProcessEvent(event);
676 }
677
678 return true ;
679 }
680 }
681 }
682 }
683
684 for (pos = 0, node = m_menuItems.First(); node; node = node->Next(), pos++)
685 {
686 wxMenuItem * pItem = (wxMenuItem *) node->Data() ;
687
688 wxMenu *pSubMenu = pItem->GetSubMenu() ;
689 if ( pSubMenu != NULL )
690 {
691 if ( pSubMenu->MacMenuSelect( handler , when , macMenuId , macMenuItemNum ) )
692 return true ;
693 }
694 }
695
696 return false ;
697 }
698
699 // Menu Bar
700
701 /*
702
703 Mac Implementation note :
704
705 The Mac has only one global menubar, so we attempt to install the currently
706 active menubar from a frame, we currently don't take into account mdi-frames
707 which would ask for menu-merging
708
709 Secondly there is no mac api for changing a menubar that is not the current
710 menubar, so we have to wait for preparing the actual menubar until the
711 wxMenubar is to be used
712
713 We can in subsequent versions use MacInstallMenuBar to provide some sort of
714 auto-merge for MDI in case this will be necessary
715
716 */
717
718 wxMenuBar* wxMenuBar::s_macInstalledMenuBar = NULL ;
719
720 wxMenuBar::wxMenuBar()
721 {
722 m_eventHandler = this;
723 m_menuCount = 0;
724 m_menus = NULL;
725 m_titles = NULL;
726 m_menuBarFrame = NULL;
727 }
728
729 wxMenuBar::wxMenuBar(int n, wxMenu *menus[], const wxString titles[])
730 {
731 m_eventHandler = this;
732 m_menuCount = n;
733 m_menus = menus;
734 m_titles = new wxString[n];
735 int i;
736 for ( i = 0; i < n; i++ )
737 m_titles[i] = titles[i];
738 m_menuBarFrame = NULL;
739 }
740
741 wxMenuBar::~wxMenuBar()
742 {
743 if (s_macInstalledMenuBar == this)
744 {
745 ::ClearMenuBar();
746 s_macInstalledMenuBar = NULL;
747 }
748
749 int i;
750 for (i = 0; i < m_menuCount; i++)
751 {
752 delete m_menus[i];
753 }
754 delete[] m_menus;
755 delete[] m_titles;
756
757 }
758
759 void wxMenuBar::MacInstallMenuBar()
760 {
761 Handle menubar = ::GetNewMBar( kwxMacMenuBarResource ) ;
762 wxString message ;
763 wxCHECK_RET( menubar != NULL, "can't read MBAR resource" );
764 ::SetMenuBar( menubar ) ;
765 ::DisposeHandle( menubar ) ;
766
767 MenuHandle menu = ::GetMenuHandle( kwxMacAppleMenuId ) ;
768 ::AppendResMenu(menu, 'DRVR');
769
770 for (int i = 0; i < m_menuCount; i++)
771 {
772 Str255 label;
773 wxNode *node;
774 wxMenuItem *item;
775 int pos ;
776 wxMenu* menu = m_menus[i] , *subMenu = NULL ;
777
778
779 if( m_titles[i] == "?" || m_titles[i] == wxApp::s_macHelpMenuTitleName )
780 {
781 MenuHandle mh = NULL ;
782 if ( HMGetHelpMenuHandle( &mh ) != noErr )
783 {
784 continue ;
785 }
786 if ( formerHelpMenuItems == 0 )
787 {
788 if( mh )
789 formerHelpMenuItems = CountMenuItems( mh ) ;
790 }
791
792 for (pos = 0 , node = menu->m_menuItems.First(); node; node = node->Next(), pos++)
793 {
794 item = (wxMenuItem *)node->Data();
795 subMenu = item->GetSubMenu() ;
796 if (subMenu)
797 {
798 // we don't support hierarchical menus in the help menu yet
799 }
800 else
801 {
802 Str255 label ;
803 wxMacBuildMenuString( label , NULL , NULL , item->GetName(), item->GetId() != wxApp::s_macAboutMenuItemId); // no shortcut in about menu
804 if ( label[0] == 0 )
805 {
806 // we cannot add empty menus on mac
807 label[0] = 1 ;
808 label[1] = ' ' ;
809 }
810 if ( item->GetId() == wxApp::s_macAboutMenuItemId )
811 {
812 ::SetMenuItemText( GetMenuHandle( kwxMacAppleMenuId ) , 1 , label );
813 // ::EnableMenuItem( GetMenuHandle( kwxMacAppleMenuId ) , 1 );
814 ::EnableItem( GetMenuHandle( kwxMacAppleMenuId ) , 1 );
815 }
816 else
817 {
818 if ( mh )
819 ::AppendMenu(mh, label );
820 }
821 }
822 }
823 }
824 else
825 {
826 wxMacBuildMenuString( label, NULL , NULL , m_titles[i] , false );
827 UMASetMenuTitle( menu->m_macMenuHandle , label ) ;
828 for (pos = 0, node = menu->m_menuItems.First(); node; node = node->Next(), pos++)
829 {
830 item = (wxMenuItem *)node->Data();
831 subMenu = item->GetSubMenu() ;
832 if (subMenu)
833 {
834 ::InsertMenu( subMenu->m_macMenuHandle , -1 ) ;
835 }
836 }
837 ::InsertMenu(m_menus[i]->m_macMenuHandle, 0);
838 }
839 }
840 ::DrawMenuBar() ;
841
842 s_macInstalledMenuBar = this;
843 }
844
845
846 // Must only be used AFTER menu has been attached to frame,
847 // otherwise use individual menus to enable/disable items
848 void wxMenuBar::Enable(int id, bool flag)
849 {
850 wxMenu *itemMenu = NULL;
851 wxMenuItem *item = FindItemForId(id, &itemMenu) ;
852 if (!item)
853 return;
854
855 item->Enable( flag ) ;
856 }
857
858 void wxMenuBar::EnableTop(int pos, bool flag)
859 {
860 m_menus[pos]->MacEnableMenu( flag ) ;
861 }
862
863 // Must only be used AFTER menu has been attached to frame,
864 // otherwise use individual menus
865 void wxMenuBar::Check(int id, bool flag)
866 {
867 wxMenu *itemMenu = NULL;
868 wxMenuItem *item = FindItemForId(id, &itemMenu) ;
869 if (!item)
870 return;
871
872 if (!item->IsCheckable())
873 return ;
874
875 item->Check( flag ) ;
876 }
877
878 bool wxMenuBar::Checked(int id) const
879 {
880 wxMenu *itemMenu = NULL;
881 wxMenuItem *item = FindItemForId(id, &itemMenu) ;
882 if (!item)
883 return FALSE;
884
885 if (!item->IsCheckable())
886 return FALSE ;
887
888 return item->IsChecked() ;
889 }
890
891 bool wxMenuBar::Enabled(int id) const
892 {
893 wxMenu *itemMenu = NULL;
894 wxMenuItem *item = FindItemForId(id, &itemMenu) ;
895 if (!item)
896 return FALSE;
897
898 if ( !item->IsEnabled() )
899 return FALSE ;
900
901 if ( itemMenu->m_macMenuEnabled == false )
902 return FALSE ;
903
904 while( itemMenu->m_parent )
905 {
906 itemMenu = (wxMenu*) itemMenu->m_parent ;
907 if ( itemMenu->IsKindOf( CLASSINFO( wxMenu ) ) )
908 {
909 if ( itemMenu->m_macMenuEnabled == false )
910 return FALSE ;
911 }
912 }
913
914 return TRUE ;
915 }
916
917
918 void wxMenuBar::SetLabel(int id, const wxString& label)
919 {
920 wxMenu *itemMenu = NULL;
921 wxMenuItem *item = FindItemForId(id, &itemMenu) ;
922
923 if (!item)
924 return;
925
926 itemMenu->SetLabel( id , label ) ;
927 }
928
929 wxString wxMenuBar::GetLabel(int id) const
930 {
931 wxMenu *itemMenu = NULL;
932 wxMenuItem *item = FindItemForId(id, &itemMenu) ;
933
934 if (!item)
935 return wxString("");
936
937 return itemMenu->GetLabel( id ) ;
938 }
939
940 void wxMenuBar::SetLabelTop(int pos, const wxString& label)
941 {
942 m_menus[pos]->SetTitle( label ) ;
943 }
944
945 wxString wxMenuBar::GetLabelTop(int pos) const
946 {
947 return m_menus[pos]->GetTitle() ;
948 }
949
950 bool wxMenuBar::OnDelete(wxMenu *a_menu, int pos)
951 {
952 if (s_macInstalledMenuBar == this)
953 {
954 ::DeleteMenu( a_menu->m_macMenuId /* m_menus[pos]->m_macMenuId */ ) ;
955 ::InvalMenuBar() ;
956 return TRUE ;
957 }
958 else
959 {
960 return TRUE ;
961 }
962 }
963
964 bool wxMenuBar::OnAppend(wxMenu *a_menu, const char *title)
965 {
966 if (!a_menu->m_macMenuHandle)
967 return FALSE;
968
969 if (s_macInstalledMenuBar == this)
970 {
971 Str255 label;
972 wxMacBuildMenuString( label, NULL , NULL , title , false );
973 UMASetMenuTitle( a_menu->m_macMenuHandle , label ) ;
974 ::InsertMenu( a_menu->m_macMenuHandle , 0 ) ;
975 ::InvalMenuBar() ;
976 return TRUE ;
977 }
978 else
979 {
980 return TRUE ;
981 }
982 }
983
984 void wxMenuBar::Append (wxMenu * menu, const wxString& title)
985 {
986 if (!OnAppend(menu, title))
987 return;
988
989 m_menuCount ++;
990 wxMenu **new_menus = new wxMenu *[m_menuCount];
991 wxString *new_titles = new wxString[m_menuCount];
992 int i;
993
994 for (i = 0; i < m_menuCount - 1; i++)
995 {
996 new_menus[i] = m_menus[i];
997 m_menus[i] = NULL;
998 new_titles[i] = m_titles[i];
999 m_titles[i] = "";
1000 }
1001 if (m_menus)
1002 {
1003 delete[]m_menus;
1004 delete[]m_titles;
1005 }
1006 m_menus = new_menus;
1007 m_titles = new_titles;
1008
1009 m_menus[m_menuCount - 1] = (wxMenu *)menu;
1010 m_titles[m_menuCount - 1] = title;
1011
1012 ((wxMenu *)menu)->m_menuBar = (wxMenuBar *) this;
1013 ((wxMenu *)menu)->SetParent(this);
1014 }
1015
1016 void wxMenuBar::Delete(wxMenu * menu, int i)
1017 {
1018 int j;
1019 int ii = (int) i;
1020
1021 if (menu != 0)
1022 {
1023 for (ii = 0; ii < m_menuCount; ii++)
1024 {
1025 if (m_menus[ii] == menu)
1026 break;
1027 }
1028 if (ii >= m_menuCount)
1029 return;
1030 } else
1031 {
1032 if (ii < 0 || ii >= m_menuCount)
1033 return;
1034 menu = m_menus[ii];
1035 }
1036
1037 if (!OnDelete(menu, ii))
1038 return;
1039
1040 menu->SetParent(NULL);
1041
1042 -- m_menuCount;
1043 for (j = ii; j < m_menuCount; j++)
1044 {
1045 m_menus[j] = m_menus[j + 1];
1046 m_titles[j] = m_titles[j + 1];
1047 }
1048 }
1049
1050 // Find the menu menuString, item itemString, and return the item id.
1051 // Returns -1 if none found.
1052 int wxMenuBar::FindMenuItem (const wxString& menuString, const wxString& itemString) const
1053 {
1054 char buf1[200];
1055 char buf2[200];
1056 wxStripMenuCodes ((char *)(const char *)menuString, buf1);
1057 int i;
1058 for (i = 0; i < m_menuCount; i++)
1059 {
1060 wxStripMenuCodes ((char *)(const char *)m_titles[i], buf2);
1061 if (strcmp (buf1, buf2) == 0)
1062 return m_menus[i]->FindItem (itemString);
1063 }
1064 return -1;
1065 }
1066
1067 wxMenuItem *wxMenuBar::FindItemForId (int Id, wxMenu ** itemMenu) const
1068 {
1069 if (itemMenu)
1070 *itemMenu = NULL;
1071
1072 wxMenuItem *item = NULL;
1073 int i;
1074 for (i = 0; i < m_menuCount; i++)
1075 if ((item = m_menus[i]->FindItemForId (Id, itemMenu)))
1076 return item;
1077 return NULL;
1078 }
1079
1080 void wxMenuBar::SetHelpString (int Id, const wxString& helpString)
1081 {
1082 int i;
1083 for (i = 0; i < m_menuCount; i++)
1084 {
1085 if (m_menus[i]->FindItemForId (Id))
1086 {
1087 m_menus[i]->SetHelpString (Id, helpString);
1088 return;
1089 }
1090 }
1091 }
1092
1093 wxString wxMenuBar::GetHelpString (int Id) const
1094 {
1095 int i;
1096 for (i = 0; i < m_menuCount; i++)
1097 {
1098 if (m_menus[i]->FindItemForId (Id))
1099 return wxString(m_menus[i]->GetHelpString (Id));
1100 }
1101 return wxString("");
1102 }
1103
1104 void wxMenuBar::MacMenuSelect(wxEvtHandler* handler, long when , int macMenuId, int macMenuItemNum)
1105 {
1106 // first scan fast for direct commands, i.e. menus which have these commands directly in their own list
1107
1108 if ( macMenuId == kwxMacAppleMenuId && macMenuItemNum == 1 )
1109 {
1110 wxCommandEvent event(wxEVT_COMMAND_MENU_SELECTED, wxApp::s_macAboutMenuItemId );
1111 event.m_timeStamp = when;
1112 event.SetEventObject(handler);
1113 event.SetInt( wxApp::s_macAboutMenuItemId );
1114 handler->ProcessEvent(event);
1115 }
1116 else
1117 {
1118 for (int i = 0; i < m_menuCount; i++)
1119 {
1120 if ( m_menus[i]->m_macMenuId == macMenuId ||
1121 ( macMenuId == kHMHelpMenuID && ( m_titles[i] == "?" || m_titles[i] == wxApp::s_macHelpMenuTitleName ) )
1122 )
1123 {
1124 if ( m_menus[i]->MacMenuSelect( handler , when , macMenuId , macMenuItemNum ) )
1125 return ;
1126 else
1127 {
1128 //TODO flag this as an error since it must contain the item
1129 return ;
1130 }
1131 }
1132 }
1133
1134 for (int i = 0; i < m_menuCount; i++)
1135 {
1136 if ( m_menus[i]->MacMenuSelect( handler , when , macMenuId , macMenuItemNum ) )
1137 {
1138 break ;
1139 }
1140 }
1141 }
1142 }
1143