]> git.saurik.com Git - wxWidgets.git/blob - src/mac/menu.cpp
wxDC::DoDrawRectangle hack is no longer needed
[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 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 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 (MAC_WXHMENU(m_hMenu))
92 ::DisposeMenu(MAC_WXHMENU(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(MAC_WXHMENU(m_hMenu), "\p-");
168 }
169 else
170 {
171 MacInsertMenuItem(MAC_WXHMENU(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( MAC_WXHMENU( pSubMenu->m_hMenu ) , -1 ) ;
187 }
188
189 if ( pos == (size_t)-1 )
190 {
191 UMAAppendSubMenuItem(MAC_WXHMENU(m_hMenu), label, pSubMenu->m_macMenuId);
192 }
193 else
194 {
195 UMAInsertSubMenuItem(MAC_WXHMENU(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(MAC_WXHMENU(m_hMenu), label,key,modifiers);
213 }
214 else
215 {
216 UMAInsertMenuItem(MAC_WXHMENU(m_hMenu), label , pos,key,modifiers);
217 }
218 if ( pItem->GetId() == idMenuTitle )
219 {
220 if ( pos == (size_t)-1 )
221 {
222 UMADisableMenuItem(MAC_WXHMENU(m_hMenu) , CountMenuItems(MAC_WXHMENU(m_hMenu) ) ) ;
223 }
224 else
225 {
226 UMADisableMenuItem(MAC_WXHMENU(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(MAC_WXHMENU(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(MAC_WXHMENU(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(MAC_WXHMENU(m_hMenu) , 0 ) ;
403 else
404 UMADisableMenuItem(MAC_WXHMENU(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 else if ( macMenuId == kHMHelpMenuID )
454 {
455 int menuItem = firstUserHelpMenuItem-1 ;
456 for (pos = 0, node = GetMenuItems().First(); node; node = node->Next(), pos++)
457 {
458 wxMenuItem * pItem = (wxMenuItem *) node->Data() ;
459
460 wxMenu *pSubMenu = pItem->GetSubMenu() ;
461 if ( pSubMenu != NULL )
462 {
463 }
464 else
465 {
466 if ( pItem->GetId() != wxApp::s_macAboutMenuItemId )
467 ++menuItem ;
468
469 if ( menuItem == macMenuItemNum )
470 {
471 wxCommandEvent event(wxEVT_COMMAND_MENU_SELECTED, pItem->GetId());
472 event.m_timeStamp = when;
473 event.SetEventObject(handler);
474 event.SetInt( pItem->GetId() );
475 {
476 bool processed = false ;
477 #if WXWIN_COMPATIBILITY
478 // Try a callback
479 if (m_callback)
480 {
481 (void) (*(m_callback)) (*this, event);
482 processed = TRUE;
483 }
484 #endif
485 // Try the menu's event handler
486 if ( !processed && handler)
487 {
488 processed = handler->ProcessEvent(event);
489 }
490
491 // Try the window the menu was popped up from (and up
492 // through the hierarchy)
493 if ( !processed && GetInvokingWindow())
494 processed = GetInvokingWindow()->GetEventHandler()->ProcessEvent(event);
495 }
496 return true ;
497 }
498 }
499 }
500 }
501
502 for (pos = 0, node = GetMenuItems().First(); node; node = node->Next(), pos++)
503 {
504 wxMenuItem * pItem = (wxMenuItem *) node->Data() ;
505
506 wxMenu *pSubMenu = pItem->GetSubMenu() ;
507 if ( pSubMenu != NULL )
508 {
509 if ( pSubMenu->MacMenuSelect( handler , when , macMenuId , macMenuItemNum ) )
510 return true ;
511 }
512 }
513
514 return false ;
515 }
516
517 // Menu Bar
518
519 /*
520
521 Mac Implementation note :
522
523 The Mac has only one global menubar, so we attempt to install the currently
524 active menubar from a frame, we currently don't take into account mdi-frames
525 which would ask for menu-merging
526
527 Secondly there is no mac api for changing a menubar that is not the current
528 menubar, so we have to wait for preparing the actual menubar until the
529 wxMenubar is to be used
530
531 We can in subsequent versions use MacInstallMenuBar to provide some sort of
532 auto-merge for MDI in case this will be necessary
533
534 */
535
536 wxMenuBar* wxMenuBar::s_macInstalledMenuBar = NULL ;
537
538 void wxMenuBar::Init()
539 {
540 m_eventHandler = this;
541 m_menuBarFrame = NULL;
542 }
543
544 wxMenuBar::wxMenuBar()
545 {
546 Init();
547 }
548
549 wxMenuBar::wxMenuBar( long WXUNUSED(style) )
550 {
551 Init();
552 }
553
554
555 wxMenuBar::wxMenuBar(int count, wxMenu *menus[], const wxString titles[])
556 {
557 Init();
558
559 m_titles.Alloc(count);
560
561 for ( int i = 0; i < count; i++ )
562 {
563 m_menus.Append(menus[i]);
564 m_titles.Add(titles[i]);
565
566 menus[i]->Attach(this);
567 }
568 }
569
570 wxMenuBar::~wxMenuBar()
571 {
572 if (s_macInstalledMenuBar == this)
573 {
574 ::ClearMenuBar();
575 s_macInstalledMenuBar = NULL;
576 }
577
578 }
579
580 void wxMenuBar::Refresh()
581 {
582 wxCHECK_RET( IsAttached(), wxT("can't refresh unatteched menubar") );
583
584 DrawMenuBar();
585 }
586
587 #if wxUSE_ACCEL
588
589 void wxMenuBar::RebuildAccelTable()
590 {
591 // merge the accelerators of all menus into one accel table
592 size_t nAccelCount = 0;
593 size_t i, count = GetMenuCount();
594 for ( i = 0; i < count; i++ )
595 {
596 nAccelCount += m_menus[i]->GetAccelCount();
597 }
598
599 if ( nAccelCount )
600 {
601 wxAcceleratorEntry *accelEntries = new wxAcceleratorEntry[nAccelCount];
602
603 nAccelCount = 0;
604 for ( i = 0; i < count; i++ )
605 {
606 nAccelCount += m_menus[i]->CopyAccels(&accelEntries[nAccelCount]);
607 }
608
609 m_accelTable = wxAcceleratorTable(nAccelCount, accelEntries);
610
611 delete [] accelEntries;
612 }
613 }
614
615 #endif // wxUSE_ACCEL
616 #ifdef WXMAKINGDLL
617 extern short gCurrentResource ;
618 #endif
619 void wxMenuBar::MacInstallMenuBar()
620 {
621 if ( s_macInstalledMenuBar == this )
622 return ;
623
624 wxStAppResource resload ;
625
626 Handle menubar = ::GetNewMBar( kwxMacMenuBarResource ) ;
627 wxString message ;
628 wxCHECK_RET( menubar != NULL, "can't read MBAR resource" );
629 ::SetMenuBar( menubar ) ;
630 #if TARGET_API_MAC_CARBON
631 ::DisposeMenuBar( menubar ) ;
632 #else
633 ::DisposeHandle( menubar ) ;
634 #endif
635
636 MenuHandle menu = ::GetMenuHandle( kwxMacAppleMenuId ) ;
637 #if TARGET_API_MAC_OS8
638 if ( CountMenuItems( menu ) == 2 )
639 {
640 ::AppendResMenu(menu, 'DRVR');
641 }
642 #endif
643
644 for (int i = 0; i < m_menus.GetCount(); i++)
645 {
646 Str255 label;
647 wxNode *node;
648 wxMenuItem *item;
649 int pos ;
650 wxMenu* menu = m_menus[i] , *subMenu = NULL ;
651
652 if( m_titles[i] == "?" || m_titles[i] == "&?" || m_titles[i] == wxApp::s_macHelpMenuTitleName )
653 {
654 MenuHandle mh = NULL ;
655 if ( UMAGetHelpMenu( &mh , &firstUserHelpMenuItem) != noErr )
656 {
657 continue ;
658 }
659
660 for ( int i = CountMenuItems( mh ) ; i >= firstUserHelpMenuItem ; --i )
661 {
662 DeleteMenuItem( mh , i ) ;
663 }
664
665 for (pos = 0 , node = menu->GetMenuItems().First(); node; node = node->Next(), pos++)
666 {
667 item = (wxMenuItem *)node->Data();
668 subMenu = item->GetSubMenu() ;
669 if (subMenu)
670 {
671 // we don't support hierarchical menus in the help menu yet
672 }
673 else
674 {
675 if ( item->IsSeparator() )
676 {
677 if ( mh )
678 MacAppendMenu(mh, "\p-" );
679 }
680 else
681 {
682 Str255 label ;
683 UInt8 modifiers ;
684 SInt16 key ;
685 wxMenuItem::MacBuildMenuString( label, &key , &modifiers , item->GetText(), item->GetId() != wxApp::s_macAboutMenuItemId); // no shortcut in about menu
686 if ( label[0] == 0 )
687 {
688 // we cannot add empty menus on mac
689 label[0] = 1 ;
690 label[1] = ' ' ;
691 }
692 if ( item->GetId() == wxApp::s_macAboutMenuItemId )
693 {
694 ::SetMenuItemText( GetMenuHandle( kwxMacAppleMenuId ) , 1 , label );
695 UMAEnableMenuItem( GetMenuHandle( kwxMacAppleMenuId ) , 1 );
696 }
697 else
698 {
699 if ( mh )
700 UMAAppendMenuItem(mh, label , key , modifiers );
701 }
702 }
703 }
704 }
705 }
706 else
707 {
708 wxMenuItem::MacBuildMenuString( label, NULL , NULL , m_titles[i] , false );
709 UMASetMenuTitle( MAC_WXHMENU(menu->GetHMenu()) , label ) ;
710 wxArrayPtrVoid submenus ;
711
712 for (pos = 0, node = menu->GetMenuItems().First(); node; node = node->Next(), pos++)
713 {
714 item = (wxMenuItem *)node->Data();
715 subMenu = item->GetSubMenu() ;
716 if (subMenu)
717 {
718 submenus.Add(subMenu) ;
719 }
720 }
721 ::InsertMenu(MAC_WXHMENU(m_menus[i]->GetHMenu()), 0);
722 for ( int i = 0 ; i < submenus.GetCount() ; ++i )
723 {
724 wxMenu* submenu = (wxMenu*) submenus[i] ;
725 wxNode *subnode;
726 wxMenuItem *subitem;
727 int subpos ;
728 for ( subpos = 0 , subnode = submenu->GetMenuItems().First(); subnode; subnode = subnode->Next(), subpos++)
729 {
730 subitem = (wxMenuItem *)subnode->Data();
731 wxMenu* itsSubMenu = subitem->GetSubMenu() ;
732 if (itsSubMenu)
733 {
734 submenus.Add(itsSubMenu) ;
735 }
736 }
737 ::InsertMenu( MAC_WXHMENU(submenu->GetHMenu()) , -1 ) ;
738 }
739 }
740 }
741 ::DrawMenuBar() ;
742 s_macInstalledMenuBar = this;
743 }
744
745 void wxMenuBar::EnableTop(size_t pos, bool enable)
746 {
747 wxCHECK_RET( IsAttached(), wxT("doesn't work with unattached menubars") );
748 m_menus[pos]->MacEnableMenu( enable ) ;
749 Refresh();
750 }
751
752 void wxMenuBar::SetLabelTop(size_t pos, const wxString& label)
753 {
754 wxCHECK_RET( pos < GetMenuCount(), wxT("invalid menu index") );
755
756 m_titles[pos] = label;
757
758 if ( !IsAttached() )
759 {
760 return;
761 }
762
763 m_menus[pos]->SetTitle( label ) ;
764 if (wxMenuBar::s_macInstalledMenuBar == this) // are we currently installed ?
765 {
766 ::SetMenuBar( GetMenuBar() ) ;
767 ::InvalMenuBar() ;
768 }
769 }
770
771 wxString wxMenuBar::GetLabelTop(size_t pos) const
772 {
773 wxCHECK_MSG( pos < GetMenuCount(), wxEmptyString,
774 wxT("invalid menu index in wxMenuBar::GetLabelTop") );
775
776 return m_titles[pos];
777 }
778
779 int wxMenuBar::FindMenu(const wxString& title)
780 {
781 wxString menuTitle = wxStripMenuCodes(title);
782
783 size_t count = GetMenuCount();
784 for ( size_t i = 0; i < count; i++ )
785 {
786 wxString title = wxStripMenuCodes(m_titles[i]);
787 if ( menuTitle == title )
788 return i;
789 }
790
791 return wxNOT_FOUND;
792
793 }
794
795
796 // ---------------------------------------------------------------------------
797 // wxMenuBar construction
798 // ---------------------------------------------------------------------------
799
800 // ---------------------------------------------------------------------------
801 // wxMenuBar construction
802 // ---------------------------------------------------------------------------
803
804 wxMenu *wxMenuBar::Replace(size_t pos, wxMenu *menu, const wxString& title)
805 {
806 wxMenu *menuOld = wxMenuBarBase::Replace(pos, menu, title);
807 if ( !menuOld )
808 return FALSE;
809 m_titles[pos] = title;
810
811 if ( IsAttached() )
812 {
813 if (s_macInstalledMenuBar == this)
814 {
815 ::DeleteMenu( menuOld->MacGetMenuId() /* m_menus[pos]->MacGetMenuId() */ ) ;
816 {
817 Str255 label;
818 wxMenuItem::MacBuildMenuString( label, NULL , NULL , title , false );
819 UMASetMenuTitle( MAC_WXHMENU(menu->GetHMenu()) , label ) ;
820 if ( pos == m_menus.GetCount() - 1)
821 {
822 ::InsertMenu( MAC_WXHMENU(menu->GetHMenu()) , 0 ) ;
823 }
824 else
825 {
826 ::InsertMenu( MAC_WXHMENU(menu->GetHMenu()) , m_menus[pos+1]->MacGetMenuId() ) ;
827 }
828 }
829 }
830
831
832 #if wxUSE_ACCEL
833 if ( menuOld->HasAccels() || menu->HasAccels() )
834 {
835 // need to rebuild accell table
836 RebuildAccelTable();
837 }
838 #endif // wxUSE_ACCEL
839
840 Refresh();
841 }
842
843 return menuOld;
844 }
845
846 bool wxMenuBar::Insert(size_t pos, wxMenu *menu, const wxString& title)
847 {
848 if ( !wxMenuBarBase::Insert(pos, menu, title) )
849 return FALSE;
850
851 m_titles.Insert(title, pos);
852
853 Str255 label ;
854 wxMenuItem::MacBuildMenuString( label, NULL , NULL , title , false );
855 UMASetMenuTitle( MAC_WXHMENU(menu->GetHMenu()) , label ) ;
856
857 if ( IsAttached() )
858 {
859 if ( pos == (size_t) -1 || pos + 1 == m_menus.GetCount() )
860 {
861 ::InsertMenu( MAC_WXHMENU(menu->GetHMenu()) , 0 ) ;
862 }
863 else
864 {
865 ::InsertMenu( MAC_WXHMENU(menu->GetHMenu()) , m_menus[pos+1]->MacGetMenuId() ) ;
866 }
867
868 #if wxUSE_ACCEL
869 if ( menu->HasAccels() )
870 {
871 // need to rebuild accell table
872 RebuildAccelTable();
873 }
874 #endif // wxUSE_ACCEL
875
876 Refresh();
877 }
878
879 return TRUE;
880 }
881
882 void wxMenuBar::MacMenuSelect(wxEvtHandler* handler, long when , int macMenuId, int macMenuItemNum)
883 {
884 // first scan fast for direct commands, i.e. menus which have these commands directly in their own list
885
886 if ( macMenuId == kwxMacAppleMenuId && macMenuItemNum == 1 )
887 {
888 wxCommandEvent event(wxEVT_COMMAND_MENU_SELECTED, wxApp::s_macAboutMenuItemId );
889 event.m_timeStamp = when;
890 event.SetEventObject(handler);
891 event.SetInt( wxApp::s_macAboutMenuItemId );
892 handler->ProcessEvent(event);
893 }
894 else
895 {
896 for (int i = 0; i < m_menus.GetCount() ; i++)
897 {
898 if ( m_menus[i]->MacGetMenuId() == macMenuId || ( macMenuId == kHMHelpMenuID && ( m_titles[i] == "?" || m_titles[i] == "&?" || m_titles[i] == wxApp::s_macHelpMenuTitleName ) ) )
899 {
900 if ( m_menus[i]->MacMenuSelect( handler , when , macMenuId , macMenuItemNum ) )
901 return ;
902 else
903 {
904 //TODO flag this as an error since it must contain the item
905 return ;
906 }
907 }
908 }
909
910 for (int i = 0; i < m_menus.GetCount(); i++)
911 {
912 if ( m_menus[i]->MacMenuSelect( handler , when , macMenuId , macMenuItemNum ) )
913 {
914 break ;
915 }
916 }
917 }
918 }
919
920 wxMenu *wxMenuBar::Remove(size_t pos)
921 {
922 wxMenu *menu = wxMenuBarBase::Remove(pos);
923 if ( !menu )
924 return NULL;
925
926 if ( IsAttached() )
927 {
928 if (s_macInstalledMenuBar == this)
929 {
930 ::DeleteMenu( menu->MacGetMenuId() /* m_menus[pos]->MacGetMenuId() */ ) ;
931 }
932
933 menu->Detach();
934
935 #if wxUSE_ACCEL
936 if ( menu->HasAccels() )
937 {
938 // need to rebuild accell table
939 RebuildAccelTable();
940 }
941 #endif // wxUSE_ACCEL
942
943 Refresh();
944 }
945
946 m_titles.Remove(pos);
947
948 return menu;
949 }
950
951 bool wxMenuBar::Append(wxMenu *menu, const wxString& title)
952 {
953 WXHMENU submenu = menu ? menu->GetHMenu() : 0;
954 wxCHECK_MSG( submenu, FALSE, wxT("can't append invalid menu to menubar") );
955
956 if ( !wxMenuBarBase::Append(menu, title) )
957 return FALSE;
958
959 m_titles.Add(title);
960
961 Str255 label ;
962 wxMenuItem::MacBuildMenuString( label, NULL , NULL , title , false );
963 UMASetMenuTitle( MAC_WXHMENU(menu->GetHMenu()) , label ) ;
964
965 if ( IsAttached() )
966 {
967 if (s_macInstalledMenuBar == this)
968 {
969 ::InsertMenu( MAC_WXHMENU(menu->GetHMenu()) , 0 ) ;
970 }
971
972 #if wxUSE_ACCEL
973 if ( menu->HasAccels() )
974 {
975 // need to rebuild accell table
976 RebuildAccelTable();
977 }
978 #endif // wxUSE_ACCEL
979
980 Refresh();
981 }
982
983 return TRUE;
984 }
985
986 void wxMenuBar::Detach()
987 {
988 wxMenuBarBase::Detach() ;
989 }
990
991 void wxMenuBar::Attach(wxFrame *frame)
992 {
993 wxMenuBarBase::Attach( frame ) ;
994
995 #if wxUSE_ACCEL
996 RebuildAccelTable();
997 #endif // wxUSE_ACCEL
998 }
999 // ---------------------------------------------------------------------------
1000 // wxMenuBar searching for menu items
1001 // ---------------------------------------------------------------------------
1002
1003 // Find the itemString in menuString, and return the item id or wxNOT_FOUND
1004 int wxMenuBar::FindMenuItem(const wxString& menuString,
1005 const wxString& itemString) const
1006 {
1007 wxString menuLabel = wxStripMenuCodes(menuString);
1008 size_t count = GetMenuCount();
1009 for ( size_t i = 0; i < count; i++ )
1010 {
1011 wxString title = wxStripMenuCodes(m_titles[i]);
1012 if ( menuString == title )
1013 return m_menus[i]->FindItem(itemString);
1014 }
1015
1016 return wxNOT_FOUND;
1017 }
1018
1019 wxMenuItem *wxMenuBar::FindItem(int id, wxMenu **itemMenu) const
1020 {
1021 if ( itemMenu )
1022 *itemMenu = NULL;
1023
1024 wxMenuItem *item = NULL;
1025 size_t count = GetMenuCount();
1026 for ( size_t i = 0; !item && (i < count); i++ )
1027 {
1028 item = m_menus[i]->FindItem(id, itemMenu);
1029 }
1030
1031 return item;
1032 }
1033
1034