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