]> git.saurik.com Git - wxWidgets.git/blob - src/mac/carbon/menu.cpp
another attempt to fix wxPanel/wxFrame::m_winLastFocused handling
[wxWidgets.git] / src / mac / carbon / menu.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: menu.cpp
3 // Purpose: wxMenu, wxMenuBar, wxMenuItem
4 // Author: AUTHOR
5 // Modified by:
6 // Created: ??/??/98
7 // RCS-ID: $Id$
8 // Copyright: (c) AUTHOR
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12
13 // ============================================================================
14 // headers & declarations
15 // ============================================================================
16
17 // wxWindows headers
18 // -----------------
19
20 #ifdef __GNUG__
21 #pragma implementation "menu.h"
22 #pragma implementation "menuitem.h"
23 #endif
24
25 #include "wx/app.h"
26 #include "wx/menu.h"
27 #include "wx/menuitem.h"
28 #include "wx/window.h"
29 #include "wx/log.h"
30 #include "wx/utils.h"
31
32 #include "wx/mac/uma.h"
33
34 // other standard headers
35 // ----------------------
36 #include <string.h>
37
38 #if !USE_SHARED_LIBRARY
39 IMPLEMENT_DYNAMIC_CLASS(wxMenu, wxEvtHandler)
40 IMPLEMENT_DYNAMIC_CLASS(wxMenuBar, wxEvtHandler)
41 #endif
42
43 // the (popup) menu title has this special id
44 static const int idMenuTitle = -2;
45 static 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 __UNIX__
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 = UMANewMenu(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 UMADisposeMenu(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.Remove(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 UMAInsertMenu( 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.Remove(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 void wxMenu::Attach(wxMenuBar *menubar)
351 {
352 // menu can be in at most one menubar because otherwise they would both
353 // delete the menu pointer
354 wxASSERT_MSG( !m_menuBar, wxT("menu belongs to 2 menubars, expect a crash") );
355
356 m_menuBar = menubar;
357 }
358
359 void wxMenu::Detach()
360 {
361 wxASSERT_MSG( m_menuBar, wxT("can't detach menu if it's not attached") );
362
363 m_menuBar = NULL;
364 }
365
366 wxWindow *wxMenu::GetWindow() const
367 {
368 if ( m_invokingWindow != NULL )
369 return m_invokingWindow;
370 else if ( m_menuBar != NULL)
371 return (wxWindow *) m_menuBar->GetFrame();
372
373 return NULL;
374 }
375
376 // helper functions returning the mac menu position for a certain item, note that this is
377 // mac-wise 1 - based, i.e. the first item has index 1 whereas on MSWin it has pos 0
378
379 int wxMenu::MacGetIndexFromId( int id )
380 {
381 size_t pos;
382 wxMenuItemList::Node *node = GetMenuItems().GetFirst();
383 for ( pos = 0; node; pos++ )
384 {
385 if ( node->GetData()->GetId() == id )
386 break;
387
388 node = node->GetNext();
389 }
390
391 if (!node)
392 return 0;
393
394 return pos + 1 ;
395 }
396
397 int wxMenu::MacGetIndexFromItem( wxMenuItem *pItem )
398 {
399 size_t pos;
400 wxMenuItemList::Node *node = GetMenuItems().GetFirst();
401 for ( pos = 0; node; pos++ )
402 {
403 if ( node->GetData() == pItem )
404 break;
405
406 node = node->GetNext();
407 }
408
409 if (!node)
410 return 0;
411
412 return pos + 1 ;
413 }
414
415 void wxMenu::MacEnableMenu( bool bDoEnable )
416 {
417 if ( bDoEnable )
418 UMAEnableMenuItem( m_hMenu , 0 ) ;
419 else
420 UMADisableMenuItem( m_hMenu , 0 ) ;
421
422 ::DrawMenuBar() ;
423 }
424
425 bool wxMenu::MacMenuSelect( wxEvtHandler* handler, long when , int macMenuId, int macMenuItemNum )
426 {
427 int pos;
428 wxNode *node;
429
430 if ( m_macMenuId == macMenuId )
431 {
432 node = GetMenuItems().Nth(macMenuItemNum-1);
433 if (node)
434 {
435 wxMenuItem *pItem = (wxMenuItem*)node->Data();
436
437 if (pItem->IsCheckable())
438 pItem->Check(! pItem->IsChecked());
439
440 wxCommandEvent event(wxEVT_COMMAND_MENU_SELECTED, pItem->GetId());
441 event.m_timeStamp = when;
442 event.SetEventObject(handler);
443 event.SetInt( pItem->GetId() );
444 {
445 bool processed = false ;
446
447 #if WXWIN_COMPATIBILITY
448 // Try a callback
449 if (m_callback)
450 {
451 (void) (*(m_callback)) (*this, event);
452 processed = TRUE;
453 }
454 #endif
455 // Try the menu's event handler
456 if ( !processed && handler)
457 {
458 processed = handler->ProcessEvent(event);
459 }
460
461 // Try the window the menu was popped up from (and up
462 // through the hierarchy)
463 if ( !processed && GetInvokingWindow())
464 processed = GetInvokingWindow()->GetEventHandler()->ProcessEvent(event);
465 }
466 return true ;
467 }
468 }
469 #ifndef __WXMAC_X__
470 else if ( macMenuId == kHMHelpMenuID )
471 {
472 int menuItem = formerHelpMenuItems ;
473 for (pos = 0, node = GetMenuItems().First(); node; node = node->Next(), pos++)
474 {
475 wxMenuItem * pItem = (wxMenuItem *) node->Data() ;
476
477 wxMenu *pSubMenu = pItem->GetSubMenu() ;
478 if ( pSubMenu != NULL )
479 {
480 }
481 else
482 {
483 if ( pItem->GetId() != wxApp::s_macAboutMenuItemId )
484 ++menuItem ;
485
486 if ( menuItem == macMenuItemNum )
487 {
488 wxCommandEvent event(wxEVT_COMMAND_MENU_SELECTED, pItem->GetId());
489 event.m_timeStamp = when;
490 event.SetEventObject(handler);
491 event.SetInt( pItem->GetId() );
492 {
493 bool processed = false ;
494 #if WXWIN_COMPATIBILITY
495 // Try a callback
496 if (m_callback)
497 {
498 (void) (*(m_callback)) (*this, event);
499 processed = TRUE;
500 }
501 #endif
502 // Try the menu's event handler
503 if ( !processed && handler)
504 {
505 processed = handler->ProcessEvent(event);
506 }
507
508 // Try the window the menu was popped up from (and up
509 // through the hierarchy)
510 if ( !processed && GetInvokingWindow())
511 processed = GetInvokingWindow()->GetEventHandler()->ProcessEvent(event);
512 }
513 return true ;
514 }
515 }
516 }
517 }
518 #endif // __WXMAC_X__
519
520 for (pos = 0, node = GetMenuItems().First(); node; node = node->Next(), pos++)
521 {
522 wxMenuItem * pItem = (wxMenuItem *) node->Data() ;
523
524 wxMenu *pSubMenu = pItem->GetSubMenu() ;
525 if ( pSubMenu != NULL )
526 {
527 if ( pSubMenu->MacMenuSelect( handler , when , macMenuId , macMenuItemNum ) )
528 return true ;
529 }
530 }
531
532 return false ;
533 }
534
535 // Menu Bar
536
537 /*
538
539 Mac Implementation note :
540
541 The Mac has only one global menubar, so we attempt to install the currently
542 active menubar from a frame, we currently don't take into account mdi-frames
543 which would ask for menu-merging
544
545 Secondly there is no mac api for changing a menubar that is not the current
546 menubar, so we have to wait for preparing the actual menubar until the
547 wxMenubar is to be used
548
549 We can in subsequent versions use MacInstallMenuBar to provide some sort of
550 auto-merge for MDI in case this will be necessary
551
552 */
553
554 wxMenuBar* wxMenuBar::s_macInstalledMenuBar = NULL ;
555
556 void wxMenuBar::Init()
557 {
558 m_eventHandler = this;
559 m_menuBarFrame = NULL;
560 }
561
562 wxMenuBar::wxMenuBar()
563 {
564 Init();
565 }
566
567 wxMenuBar::wxMenuBar( long WXUNUSED(style) )
568 {
569 Init();
570 }
571
572
573 wxMenuBar::wxMenuBar(int count, wxMenu *menus[], const wxString titles[])
574 {
575 Init();
576
577 m_titles.Alloc(count);
578
579 for ( int i = 0; i < count; i++ )
580 {
581 m_menus.Append(menus[i]);
582 m_titles.Add(titles[i]);
583
584 menus[i]->Attach(this);
585 }
586 }
587
588 wxMenuBar::~wxMenuBar()
589 {
590 if (s_macInstalledMenuBar == this)
591 {
592 ::ClearMenuBar();
593 s_macInstalledMenuBar = NULL;
594 }
595
596 }
597
598 void wxMenuBar::Refresh()
599 {
600 wxCHECK_RET( IsAttached(), wxT("can't refresh unatteched menubar") );
601
602 DrawMenuBar();
603 }
604
605 #if wxUSE_ACCEL
606
607 void wxMenuBar::RebuildAccelTable()
608 {
609 // merge the accelerators of all menus into one accel table
610 size_t nAccelCount = 0;
611 size_t i, count = GetMenuCount();
612 for ( i = 0; i < count; i++ )
613 {
614 nAccelCount += m_menus[i]->GetAccelCount();
615 }
616
617 if ( nAccelCount )
618 {
619 wxAcceleratorEntry *accelEntries = new wxAcceleratorEntry[nAccelCount];
620
621 nAccelCount = 0;
622 for ( i = 0; i < count; i++ )
623 {
624 nAccelCount += m_menus[i]->CopyAccels(&accelEntries[nAccelCount]);
625 }
626
627 m_accelTable = wxAcceleratorTable(nAccelCount, accelEntries);
628
629 delete [] accelEntries;
630 }
631 }
632
633 #endif // wxUSE_ACCEL
634
635
636 void wxMenuBar::MacInstallMenuBar()
637 {
638 if ( s_macInstalledMenuBar == this )
639 return ;
640
641 Handle menubar = ::GetNewMBar( kwxMacMenuBarResource ) ;
642 wxString message ;
643 wxCHECK_RET( menubar != NULL, "can't read MBAR resource" );
644 ::SetMenuBar( menubar ) ;
645 ::DisposeHandle( menubar ) ;
646
647 MenuHandle menu = ::GetMenuHandle( kwxMacAppleMenuId ) ;
648 ::AppendResMenu(menu, 'DRVR');
649
650 for (int i = 0; i < m_menus.GetCount(); i++)
651 {
652 Str255 label;
653 wxNode *node;
654 wxMenuItem *item;
655 int pos ;
656 wxMenu* menu = m_menus[i] , *subMenu = NULL ;
657
658 #if !TARGET_CARBON
659 /* the help menu does not exist in CARBON anymore */
660 if( m_titles[i] == "?" || m_titles[i] == "&?" || m_titles[i] == wxApp::s_macHelpMenuTitleName )
661 {
662 MenuHandle mh = NULL ;
663 if ( HMGetHelpMenuHandle( &mh ) != noErr )
664 {
665 continue ;
666 }
667 if ( formerHelpMenuItems == 0 )
668 {
669 if( mh )
670 formerHelpMenuItems = CountMenuItems( mh ) ;
671 }
672
673 for (pos = 0 , node = menu->GetMenuItems().First(); node; node = node->Next(), pos++)
674 {
675 item = (wxMenuItem *)node->Data();
676 subMenu = item->GetSubMenu() ;
677 if (subMenu)
678 {
679 // we don't support hierarchical menus in the help menu yet
680 }
681 else
682 {
683 if ( item->IsSeparator() )
684 {
685 if ( mh )
686 UMAAppendMenuItem(mh, "\p-" );
687 }
688 else
689 {
690 Str255 label ;
691 UInt8 modifiers ;
692 SInt16 key ;
693 wxMenuItem::MacBuildMenuString( label, &key , &modifiers , item->GetText(), item->GetId() != wxApp::s_macAboutMenuItemId); // no shortcut in about menu
694 if ( label[0] == 0 )
695 {
696 // we cannot add empty menus on mac
697 label[0] = 1 ;
698 label[1] = ' ' ;
699 }
700 if ( item->GetId() == wxApp::s_macAboutMenuItemId )
701 {
702 UMASetMenuItemText( GetMenuHandle( kwxMacAppleMenuId ) , 1 , label );
703 UMAEnableMenuItem( GetMenuHandle( kwxMacAppleMenuId ) , 1 );
704 }
705 else
706 {
707 if ( mh )
708 UMAAppendMenuItem(mh, label , key , modifiers );
709 }
710 }
711 }
712 }
713 }
714 #else
715 if( m_titles[i] == "?" || m_titles[i] == "&?" || m_titles[i] == wxApp::s_macHelpMenuTitleName )
716 {
717 wxMenuItem::MacBuildMenuString( label, NULL , NULL , m_titles[i] , false );
718 UMASetMenuTitle( menu->GetHMenu() , label ) ;
719
720 for (pos = 0 , node = menu->GetMenuItems().First(); node; node = node->Next(), pos++)
721 {
722 item = (wxMenuItem *)node->Data();
723 subMenu = item->GetSubMenu() ;
724 if (subMenu)
725 {
726 UMAInsertMenu( subMenu->GetHMenu() , -1 ) ;
727 }
728 else
729 {
730 if ( item->GetId() == wxApp::s_macAboutMenuItemId )
731 {
732 Str255 label ;
733 UInt8 modifiers ;
734 SInt16 key ;
735 wxMenuItem::MacBuildMenuString( label, &key , &modifiers , item->GetText(), item->GetId() != wxApp::s_macAboutMenuItemId); // no shortcut in about menu
736 UMASetMenuItemText( GetMenuHandle( kwxMacAppleMenuId ) , 1 , label );
737 UMAEnableMenuItem( GetMenuHandle( kwxMacAppleMenuId ) , 1 );
738 }
739 }
740 }
741 UMAInsertMenu(m_menus[i]->GetHMenu(), 0);
742 }
743 #endif
744 else
745 {
746 wxMenuItem::MacBuildMenuString( label, NULL , NULL , m_titles[i] , false );
747 UMASetMenuTitle( menu->GetHMenu() , label ) ;
748 for (pos = 0, node = menu->GetMenuItems().First(); node; node = node->Next(), pos++)
749 {
750 item = (wxMenuItem *)node->Data();
751 subMenu = item->GetSubMenu() ;
752 if (subMenu)
753 {
754 UMAInsertMenu( subMenu->GetHMenu() , -1 ) ;
755 }
756 }
757 UMAInsertMenu(m_menus[i]->GetHMenu(), 0);
758 }
759 }
760 UMADrawMenuBar() ;
761
762 s_macInstalledMenuBar = this;
763 }
764
765 void wxMenuBar::EnableTop(size_t pos, bool enable)
766 {
767 wxCHECK_RET( IsAttached(), wxT("doesn't work with unattached menubars") );
768 m_menus[pos]->MacEnableMenu( enable ) ;
769 Refresh();
770 }
771
772 void wxMenuBar::SetLabelTop(size_t pos, const wxString& label)
773 {
774 wxCHECK_RET( pos < GetMenuCount(), wxT("invalid menu index") );
775
776 m_titles[pos] = label;
777
778 if ( !IsAttached() )
779 {
780 return;
781 }
782
783 m_menus[pos]->SetTitle( label ) ;
784 if (wxMenuBar::s_macInstalledMenuBar == this) // are we currently installed ?
785 {
786 ::SetMenuBar( GetMenuBar() ) ;
787 ::InvalMenuBar() ;
788 }
789 }
790
791 wxString wxMenuBar::GetLabelTop(size_t pos) const
792 {
793 wxCHECK_MSG( pos < GetMenuCount(), wxEmptyString,
794 wxT("invalid menu index in wxMenuBar::GetLabelTop") );
795
796 return m_titles[pos];
797 }
798
799 int wxMenuBar::FindMenu(const wxString& title)
800 {
801 wxString menuTitle = wxStripMenuCodes(title);
802
803 size_t count = GetMenuCount();
804 for ( size_t i = 0; i < count; i++ )
805 {
806 wxString title = wxStripMenuCodes(m_titles[i]);
807 if ( menuTitle == title )
808 return i;
809 }
810
811 return wxNOT_FOUND;
812
813 }
814
815
816 // ---------------------------------------------------------------------------
817 // wxMenuBar construction
818 // ---------------------------------------------------------------------------
819
820 // ---------------------------------------------------------------------------
821 // wxMenuBar construction
822 // ---------------------------------------------------------------------------
823
824 wxMenu *wxMenuBar::Replace(size_t pos, wxMenu *menu, const wxString& title)
825 {
826 wxMenu *menuOld = wxMenuBarBase::Replace(pos, menu, title);
827 if ( !menuOld )
828 return FALSE;
829 m_titles[pos] = title;
830
831 if ( IsAttached() )
832 {
833 if (s_macInstalledMenuBar == this)
834 {
835 UMADeleteMenu( menuOld->MacGetMenuId() /* m_menus[pos]->MacGetMenuId() */ ) ;
836 {
837 Str255 label;
838 wxMenuItem::MacBuildMenuString( label, NULL , NULL , title , false );
839 UMASetMenuTitle( menu->GetHMenu() , label ) ;
840 if ( pos == m_menus.GetCount() - 1)
841 {
842 UMAInsertMenu( menu->GetHMenu() , 0 ) ;
843 }
844 else
845 {
846 UMAInsertMenu( menu->GetHMenu() , m_menus[pos+1]->MacGetMenuId() ) ;
847 }
848 }
849 }
850
851
852 #if wxUSE_ACCEL
853 if ( menuOld->HasAccels() || menu->HasAccels() )
854 {
855 // need to rebuild accell table
856 RebuildAccelTable();
857 }
858 #endif // wxUSE_ACCEL
859
860 Refresh();
861 }
862
863 return menuOld;
864 }
865
866 bool wxMenuBar::Insert(size_t pos, wxMenu *menu, const wxString& title)
867 {
868 if ( !wxMenuBarBase::Insert(pos, menu, title) )
869 return FALSE;
870
871 m_titles.Insert(title, pos);
872
873 menu->Attach(this);
874
875 if ( IsAttached() )
876 {
877 if ( pos == (size_t) -1 )
878 {
879 ::InsertMenu( menu->GetHMenu() , 0 ) ;
880 }
881 else
882 {
883 ::InsertMenu( menu->GetHMenu() , m_menus[pos+1]->MacGetMenuId() ) ;
884 }
885
886 #if wxUSE_ACCEL
887 if ( menu->HasAccels() )
888 {
889 // need to rebuild accell table
890 RebuildAccelTable();
891 }
892 #endif // wxUSE_ACCEL
893
894 Refresh();
895 }
896
897 return TRUE;
898 }
899
900 void wxMenuBar::MacMenuSelect(wxEvtHandler* handler, long when , int macMenuId, int macMenuItemNum)
901 {
902 // first scan fast for direct commands, i.e. menus which have these commands directly in their own list
903
904 if ( macMenuId == kwxMacAppleMenuId && macMenuItemNum == 1 )
905 {
906 wxCommandEvent event(wxEVT_COMMAND_MENU_SELECTED, wxApp::s_macAboutMenuItemId );
907 event.m_timeStamp = when;
908 event.SetEventObject(handler);
909 event.SetInt( wxApp::s_macAboutMenuItemId );
910 handler->ProcessEvent(event);
911 }
912 else
913 {
914 for (int i = 0; i < m_menus.GetCount() ; i++)
915 {
916 if ( m_menus[i]->MacGetMenuId() == macMenuId
917 #ifndef __WXMAC_X__
918 ||
919 ( macMenuId == kHMHelpMenuID && ( m_titles[i] == "?" || m_titles[i] == "&?" || m_titles[i] == wxApp::s_macHelpMenuTitleName ) )
920 #endif
921 )
922 {
923 if ( m_menus[i]->MacMenuSelect( handler , when , macMenuId , macMenuItemNum ) )
924 return ;
925 else
926 {
927 //TODO flag this as an error since it must contain the item
928 return ;
929 }
930 }
931 }
932
933 for (int i = 0; i < m_menus.GetCount(); i++)
934 {
935 if ( m_menus[i]->MacMenuSelect( handler , when , macMenuId , macMenuItemNum ) )
936 {
937 break ;
938 }
939 }
940 }
941 }
942
943 wxMenu *wxMenuBar::Remove(size_t pos)
944 {
945 wxMenu *menu = wxMenuBarBase::Remove(pos);
946 if ( !menu )
947 return NULL;
948
949 if ( IsAttached() )
950 {
951 if (s_macInstalledMenuBar == this)
952 {
953 ::DeleteMenu( menu->MacGetMenuId() /* m_menus[pos]->MacGetMenuId() */ ) ;
954 }
955
956 menu->Detach();
957
958 #if wxUSE_ACCEL
959 if ( menu->HasAccels() )
960 {
961 // need to rebuild accell table
962 RebuildAccelTable();
963 }
964 #endif // wxUSE_ACCEL
965
966 Refresh();
967 }
968
969 m_titles.Remove(pos);
970
971 return menu;
972 }
973
974 bool wxMenuBar::Append(wxMenu *menu, const wxString& title)
975 {
976 WXHMENU submenu = menu ? menu->GetHMenu() : 0;
977 wxCHECK_MSG( submenu, FALSE, wxT("can't append invalid menu to menubar") );
978
979 if ( !wxMenuBarBase::Append(menu, title) )
980 return FALSE;
981
982 menu->Attach(this);
983
984 m_titles.Add(title);
985
986 if ( IsAttached() )
987 {
988 if (s_macInstalledMenuBar == this)
989 {
990 ::InsertMenu( menu->GetHMenu() , 0 ) ;
991 }
992
993 #if wxUSE_ACCEL
994 if ( menu->HasAccels() )
995 {
996 // need to rebuild accell table
997 RebuildAccelTable();
998 }
999 #endif // wxUSE_ACCEL
1000
1001 Refresh();
1002 }
1003
1004 return TRUE;
1005 }
1006
1007 void wxMenuBar::Attach(wxFrame *frame)
1008 {
1009 // wxASSERT_MSG( !IsAttached(), wxT("menubar already attached!") );
1010
1011 m_menuBarFrame = frame;
1012
1013 #if wxUSE_ACCEL
1014 RebuildAccelTable();
1015 #endif // wxUSE_ACCEL
1016 }
1017 // ---------------------------------------------------------------------------
1018 // wxMenuBar searching for menu items
1019 // ---------------------------------------------------------------------------
1020
1021 // Find the itemString in menuString, and return the item id or wxNOT_FOUND
1022 int wxMenuBar::FindMenuItem(const wxString& menuString,
1023 const wxString& itemString) const
1024 {
1025 wxString menuLabel = wxStripMenuCodes(menuString);
1026 size_t count = GetMenuCount();
1027 for ( size_t i = 0; i < count; i++ )
1028 {
1029 wxString title = wxStripMenuCodes(m_titles[i]);
1030 if ( menuString == title )
1031 return m_menus[i]->FindItem(itemString);
1032 }
1033
1034 return wxNOT_FOUND;
1035 }
1036
1037 wxMenuItem *wxMenuBar::FindItem(int id, wxMenu **itemMenu) const
1038 {
1039 if ( itemMenu )
1040 *itemMenu = NULL;
1041
1042 wxMenuItem *item = NULL;
1043 size_t count = GetMenuCount();
1044 for ( size_t i = 0; !item && (i < count); i++ )
1045 {
1046 item = m_menus[i]->FindItem(id, itemMenu);
1047 }
1048
1049 return item;
1050 }
1051
1052