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