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