]> git.saurik.com Git - wxWidgets.git/blob - src/msw/menu.cpp
help search is much faster now (7 times! that's what I call optimization ;-)
[wxWidgets.git] / src / msw / menu.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: menu.cpp
3 // Purpose: wxMenu, wxMenuBar, wxMenuItem
4 // Author: Julian Smart
5 // Modified by: Vadim Zeitlin
6 // Created: 04/01/98
7 // RCS-ID: $Id$
8 // Copyright: (c) Julian Smart and Markus Holzem
9 // Licence: wxWindows license
10 /////////////////////////////////////////////////////////////////////////////
11
12 // ===========================================================================
13 // declarations
14 // ===========================================================================
15
16 // ---------------------------------------------------------------------------
17 // headers
18 // ---------------------------------------------------------------------------
19
20 #ifdef __GNUG__
21 #pragma implementation "menu.h"
22 #endif
23
24 // For compilers that support precompilation, includes "wx.h".
25 #include "wx/wxprec.h"
26
27 #ifdef __BORLANDC__
28 #pragma hdrstop
29 #endif
30
31 #ifndef WX_PRECOMP
32 #include "wx/frame.h"
33 #include "wx/menu.h"
34 #include "wx/utils.h"
35 #include "wx/intl.h"
36 #include "wx/log.h"
37 #endif
38
39 #if wxUSE_OWNER_DRAWN
40 #include "wx/ownerdrw.h"
41 #endif
42
43 #include "wx/msw/private.h"
44
45 // other standard headers
46 #include <string.h>
47
48 // ----------------------------------------------------------------------------
49 // global variables
50 // ----------------------------------------------------------------------------
51
52 extern wxMenu *wxCurrentPopupMenu;
53
54 // ----------------------------------------------------------------------------
55 // constants
56 // ----------------------------------------------------------------------------
57
58 // the (popup) menu title has this special id
59 static const int idMenuTitle = -2;
60
61 // ----------------------------------------------------------------------------
62 // macros
63 // ----------------------------------------------------------------------------
64
65 IMPLEMENT_DYNAMIC_CLASS(wxMenu, wxEvtHandler)
66 IMPLEMENT_DYNAMIC_CLASS(wxMenuBar, wxEvtHandler)
67
68 // ============================================================================
69 // implementation
70 // ============================================================================
71
72 // ---------------------------------------------------------------------------
73 // wxMenu construction, adding and removing menu items
74 // ---------------------------------------------------------------------------
75
76 // Construct a menu with optional title (then use append)
77 void wxMenu::Init()
78 {
79 m_doBreak = FALSE;
80
81 // create the menu
82 m_hMenu = (WXHMENU)CreatePopupMenu();
83 if ( !m_hMenu )
84 {
85 wxLogLastError("CreatePopupMenu");
86 }
87
88 // if we have a title, insert it in the beginning of the menu
89 if ( !!m_title )
90 {
91 Append(idMenuTitle, m_title);
92 AppendSeparator();
93 }
94 }
95
96 // The wxWindow destructor will take care of deleting the submenus.
97 wxMenu::~wxMenu()
98 {
99 // we should free Windows resources only if Windows doesn't do it for us
100 // which happens if we're attached to a menubar or a submenu of another
101 // menu
102 if ( !IsAttached() && !GetParent() )
103 {
104 if ( !::DestroyMenu(GetHmenu()) )
105 {
106 wxLogLastError("DestroyMenu");
107 }
108 }
109
110 #if wxUSE_ACCEL
111 // delete accels
112 WX_CLEAR_ARRAY(m_accels);
113 #endif // wxUSE_ACCEL
114 }
115
116 void wxMenu::Break()
117 {
118 // this will take effect during the next call to Append()
119 m_doBreak = TRUE;
120 }
121
122 #if wxUSE_ACCEL
123
124 int wxMenu::FindAccel(int id) const
125 {
126 size_t n, count = m_accels.GetCount();
127 for ( n = 0; n < count; n++ )
128 {
129 if ( m_accels[n]->m_command == id )
130 return n;
131 }
132
133 return wxNOT_FOUND;
134 }
135
136 void wxMenu::UpdateAccel(wxMenuItem *item)
137 {
138 // find the (new) accel for this item
139 wxAcceleratorEntry *accel = wxGetAccelFromString(item->GetText());
140 if ( accel )
141 accel->m_command = item->GetId();
142
143 // find the old one
144 int n = FindAccel(item->GetId());
145 if ( n == wxNOT_FOUND )
146 {
147 // no old, add new if any
148 if ( accel )
149 m_accels.Add(accel);
150 else
151 return; // skipping RebuildAccelTable() below
152 }
153 else
154 {
155 // replace old with new or just remove the old one if no new
156 delete m_accels[n];
157 if ( accel )
158 m_accels[n] = accel;
159 else
160 m_accels.Remove(n);
161 }
162
163 if ( IsAttached() )
164 {
165 m_menuBar->RebuildAccelTable();
166 }
167 }
168
169 #endif // wxUSE_ACCEL
170
171 // append a new item or submenu to the menu
172 bool wxMenu::DoInsertOrAppend(wxMenuItem *pItem, size_t pos)
173 {
174 #if wxUSE_ACCEL
175 UpdateAccel(pItem);
176 #endif // wxUSE_ACCEL
177
178 UINT flags = 0;
179
180 // if "Break" has just been called, insert a menu break before this item
181 // (and don't forget to reset the flag)
182 if ( m_doBreak ) {
183 flags |= MF_MENUBREAK;
184 m_doBreak = FALSE;
185 }
186
187 if ( pItem->IsSeparator() ) {
188 flags |= MF_SEPARATOR;
189 }
190
191 // id is the numeric id for normal menu items and HMENU for submenus as
192 // required by ::AppendMenu() API
193 UINT id;
194 wxMenu *submenu = pItem->GetSubMenu();
195 if ( submenu != NULL ) {
196 wxASSERT_MSG( submenu->GetHMenu(), wxT("invalid submenu") );
197
198 submenu->SetParent(this);
199
200 id = (UINT)submenu->GetHMenu();
201
202 flags |= MF_POPUP;
203 }
204 else {
205 id = pItem->GetId();
206 }
207
208 LPCTSTR pData;
209
210 #if wxUSE_OWNER_DRAWN
211 if ( pItem->IsOwnerDrawn() ) { // want to get {Measure|Draw}Item messages?
212 // item draws itself, pass pointer to it in data parameter
213 flags |= MF_OWNERDRAW;
214 pData = (LPCTSTR)pItem;
215 }
216 else
217 #endif
218 {
219 // menu is just a normal string (passed in data parameter)
220 flags |= MF_STRING;
221
222 pData = (wxChar*)pItem->GetText().c_str();
223 }
224
225 BOOL ok;
226 if ( pos == (size_t)-1 )
227 {
228 ok = ::AppendMenu(GetHmenu(), flags, id, pData);
229 }
230 else
231 {
232 ok = ::InsertMenu(GetHmenu(), pos, flags | MF_BYPOSITION, id, pData);
233 }
234
235 if ( !ok )
236 {
237 wxLogLastError("Insert or AppendMenu");
238
239 return FALSE;
240 }
241 else
242 {
243 // if we just appended the title, highlight it
244 #ifdef __WIN32__
245 if ( (int)id == idMenuTitle )
246 {
247 // visually select the menu title
248 MENUITEMINFO mii;
249 mii.cbSize = sizeof(mii);
250 mii.fMask = MIIM_STATE;
251 mii.fState = MFS_DEFAULT;
252
253 if ( !SetMenuItemInfo(GetHmenu(), (unsigned)id, FALSE, &mii) )
254 {
255 wxLogLastError(wxT("SetMenuItemInfo"));
256 }
257 }
258 #endif // __WIN32__
259
260 // if we're already attached to the menubar, we must update it
261 if ( IsAttached() )
262 {
263 m_menuBar->Refresh();
264 }
265
266 return TRUE;
267 }
268 }
269
270 bool wxMenu::DoAppend(wxMenuItem *item)
271 {
272 return wxMenuBase::DoAppend(item) && DoInsertOrAppend(item);
273 }
274
275 bool wxMenu::DoInsert(size_t pos, wxMenuItem *item)
276 {
277 return wxMenuBase::DoInsert(pos, item) && DoInsertOrAppend(item, pos);
278 }
279
280 wxMenuItem *wxMenu::DoRemove(wxMenuItem *item)
281 {
282 // we need to find the items position in the child list
283 size_t pos;
284 wxMenuItemList::Node *node = GetMenuItems().GetFirst();
285 for ( pos = 0; node; pos++ )
286 {
287 if ( node->GetData() == item )
288 break;
289
290 node = node->GetNext();
291 }
292
293 // DoRemove() (unlike Remove) can only be called for existing item!
294 wxCHECK_MSG( node, NULL, wxT("bug in wxMenu::Remove logic") );
295
296 #if wxUSE_ACCEL
297 // remove the corresponding accel from the accel table
298 int n = FindAccel(item->GetId());
299 if ( n != wxNOT_FOUND )
300 {
301 delete m_accels[n];
302
303 m_accels.Remove(n);
304 }
305 //else: this item doesn't have an accel, nothing to do
306 #endif // wxUSE_ACCEL
307
308 // remove the item from the menu
309 if ( !::RemoveMenu(GetHmenu(), (UINT)pos, MF_BYPOSITION) )
310 {
311 wxLogLastError("RemoveMenu");
312 }
313
314 if ( IsAttached() )
315 {
316 // otherwise, the chane won't be visible
317 m_menuBar->Refresh();
318 }
319
320 // and from internal data structures
321 return wxMenuBase::DoRemove(item);
322 }
323
324 // ---------------------------------------------------------------------------
325 // accelerator helpers
326 // ---------------------------------------------------------------------------
327
328 #if wxUSE_ACCEL
329
330 // create the wxAcceleratorEntries for our accels and put them into provided
331 // array - return the number of accels we have
332 size_t wxMenu::CopyAccels(wxAcceleratorEntry *accels) const
333 {
334 size_t count = GetAccelCount();
335 for ( size_t n = 0; n < count; n++ )
336 {
337 *accels++ = *m_accels[n];
338 }
339
340 return count;
341 }
342
343 #endif // wxUSE_ACCEL
344
345 // ---------------------------------------------------------------------------
346 // set wxMenu title
347 // ---------------------------------------------------------------------------
348
349 void wxMenu::SetTitle(const wxString& label)
350 {
351 bool hasNoTitle = m_title.IsEmpty();
352 m_title = label;
353
354 HMENU hMenu = GetHmenu();
355
356 if ( hasNoTitle )
357 {
358 if ( !label.IsEmpty() )
359 {
360 if ( !::InsertMenu(hMenu, 0u, MF_BYPOSITION | MF_STRING,
361 (unsigned)idMenuTitle, m_title) ||
362 !::InsertMenu(hMenu, 1u, MF_BYPOSITION, (unsigned)-1, NULL) )
363 {
364 wxLogLastError("InsertMenu");
365 }
366 }
367 }
368 else
369 {
370 if ( label.IsEmpty() )
371 {
372 // remove the title and the separator after it
373 if ( !RemoveMenu(hMenu, 0, MF_BYPOSITION) ||
374 !RemoveMenu(hMenu, 0, MF_BYPOSITION) )
375 {
376 wxLogLastError("RemoveMenu");
377 }
378 }
379 else
380 {
381 // modify the title
382 if ( !ModifyMenu(hMenu, 0u,
383 MF_BYPOSITION | MF_STRING,
384 (unsigned)idMenuTitle, m_title) )
385 {
386 wxLogLastError("ModifyMenu");
387 }
388 }
389 }
390
391 #ifdef __WIN32__
392 // put the title string in bold face
393 if ( !m_title.IsEmpty() )
394 {
395 MENUITEMINFO mii;
396 mii.cbSize = sizeof(mii);
397 mii.fMask = MIIM_STATE;
398 mii.fState = MFS_DEFAULT;
399
400 if ( !SetMenuItemInfo(hMenu, (unsigned)idMenuTitle, FALSE, &mii) )
401 {
402 wxLogLastError("SetMenuItemInfo");
403 }
404 }
405 #endif // Win32
406 }
407
408 // ---------------------------------------------------------------------------
409 // event processing
410 // ---------------------------------------------------------------------------
411
412 bool wxMenu::MSWCommand(WXUINT WXUNUSED(param), WXWORD id)
413 {
414 // ignore commands from the menu title
415
416 // NB: VC++ generates wrong assembler for `if ( id != idMenuTitle )'!!
417 if ( id != (WXWORD)idMenuTitle )
418 {
419 wxCommandEvent event(wxEVT_COMMAND_MENU_SELECTED);
420 event.SetEventObject( this );
421 event.SetId( id );
422 event.SetInt( id );
423 ProcessCommand(event);
424 }
425
426 return TRUE;
427 }
428
429 bool wxMenu::ProcessCommand(wxCommandEvent & event)
430 {
431 bool processed = FALSE;
432
433 #if wxUSE_MENU_CALLBACK
434 // Try a callback
435 if (m_callback)
436 {
437 (void)(*(m_callback))(*this, event);
438 processed = TRUE;
439 }
440 #endif // wxUSE_MENU_CALLBACK
441
442 // Try the menu's event handler
443 if ( !processed && GetEventHandler())
444 {
445 processed = GetEventHandler()->ProcessEvent(event);
446 }
447
448 // Try the window the menu was popped up from (and up through the
449 // hierarchy)
450 wxWindow *win = GetInvokingWindow();
451 if ( !processed && win )
452 processed = win->GetEventHandler()->ProcessEvent(event);
453
454 return processed;
455 }
456
457 // ---------------------------------------------------------------------------
458 // other
459 // ---------------------------------------------------------------------------
460
461 void wxMenu::Attach(wxMenuBar *menubar)
462 {
463 // menu can be in at most one menubar because otherwise they would both
464 // delete the menu pointer
465 wxASSERT_MSG( !m_menuBar, wxT("menu belongs to 2 menubars, expect a crash") );
466
467 m_menuBar = menubar;
468 }
469
470 void wxMenu::Detach()
471 {
472 wxASSERT_MSG( m_menuBar, wxT("can't detach menu if it's not attached") );
473
474 m_menuBar = NULL;
475 }
476
477 wxWindow *wxMenu::GetWindow() const
478 {
479 if ( m_invokingWindow != NULL )
480 return m_invokingWindow;
481 else if ( m_menuBar != NULL)
482 return m_menuBar->GetFrame();
483
484 return NULL;
485 }
486
487 // ---------------------------------------------------------------------------
488 // Menu Bar
489 // ---------------------------------------------------------------------------
490
491 void wxMenuBar::Init()
492 {
493 m_eventHandler = this;
494 m_menuBarFrame = NULL;
495 m_hMenu = 0;
496 }
497
498 wxMenuBar::wxMenuBar()
499 {
500 Init();
501 }
502
503 wxMenuBar::wxMenuBar( long WXUNUSED(style) )
504 {
505 Init();
506 }
507
508 wxMenuBar::wxMenuBar(int count, wxMenu *menus[], const wxString titles[])
509 {
510 Init();
511
512 m_titles.Alloc(count);
513
514 for ( int i = 0; i < count; i++ )
515 {
516 m_menus.Append(menus[i]);
517 m_titles.Add(titles[i]);
518
519 menus[i]->Attach(this);
520 }
521 }
522
523 wxMenuBar::~wxMenuBar()
524 {
525 }
526
527 // ---------------------------------------------------------------------------
528 // wxMenuBar helpers
529 // ---------------------------------------------------------------------------
530
531 void wxMenuBar::Refresh()
532 {
533 wxCHECK_RET( IsAttached(), wxT("can't refresh unattached menubar") );
534
535 DrawMenuBar(GetHwndOf(m_menuBarFrame));
536 }
537
538 WXHMENU wxMenuBar::Create()
539 {
540 if (m_hMenu != 0 )
541 return m_hMenu;
542
543 wxCHECK_MSG( !m_hMenu, TRUE, wxT("menubar already created") );
544
545 m_hMenu = (WXHMENU)::CreateMenu();
546
547 if ( !m_hMenu )
548 {
549 wxLogLastError("CreateMenu");
550 }
551 else
552 {
553 size_t count = GetMenuCount();
554 for ( size_t i = 0; i < count; i++ )
555 {
556 if ( !::AppendMenu((HMENU)m_hMenu, MF_POPUP | MF_STRING,
557 (UINT)m_menus[i]->GetHMenu(),
558 m_titles[i]) )
559 {
560 wxLogLastError("AppendMenu");
561 }
562 }
563 }
564
565 return m_hMenu;
566 }
567
568 // ---------------------------------------------------------------------------
569 // wxMenuBar functions to work with the top level submenus
570 // ---------------------------------------------------------------------------
571
572 // NB: we don't support owner drawn top level items for now, if we do these
573 // functions would have to be changed to use wxMenuItem as well
574
575 void wxMenuBar::EnableTop(size_t pos, bool enable)
576 {
577 wxCHECK_RET( IsAttached(), wxT("doesn't work with unattached menubars") );
578
579 int flag = enable ? MF_ENABLED : MF_GRAYED;
580
581 EnableMenuItem((HMENU)m_hMenu, pos, MF_BYPOSITION | flag);
582
583 Refresh();
584 }
585
586 void wxMenuBar::SetLabelTop(size_t pos, const wxString& label)
587 {
588 wxCHECK_RET( pos < GetMenuCount(), wxT("invalid menu index") );
589
590 m_titles[pos] = label;
591
592 if ( !IsAttached() )
593 {
594 return;
595 }
596 //else: have to modify the existing menu
597
598 UINT id;
599 UINT flagsOld = ::GetMenuState((HMENU)m_hMenu, pos, MF_BYPOSITION);
600 if ( flagsOld == 0xFFFFFFFF )
601 {
602 wxLogLastError(wxT("GetMenuState"));
603
604 return;
605 }
606
607 if ( flagsOld & MF_POPUP )
608 {
609 // HIBYTE contains the number of items in the submenu in this case
610 flagsOld &= 0xff;
611 id = (UINT)::GetSubMenu((HMENU)m_hMenu, pos);
612 }
613 else
614 {
615 id = pos;
616 }
617
618 if ( ::ModifyMenu(GetHmenu(), pos, MF_BYPOSITION | MF_STRING | flagsOld,
619 id, label) == (int)0xFFFFFFFF )
620 {
621 wxLogLastError("ModifyMenu");
622 }
623
624 Refresh();
625 }
626
627 wxString wxMenuBar::GetLabelTop(size_t pos) const
628 {
629 wxCHECK_MSG( pos < GetMenuCount(), wxEmptyString,
630 wxT("invalid menu index in wxMenuBar::GetLabelTop") );
631
632 return m_titles[pos];
633 }
634
635 int wxMenuBar::FindMenu(const wxString& title)
636 {
637 wxString menuTitle = wxStripMenuCodes(title);
638
639 size_t count = GetMenuCount();
640 for ( size_t i = 0; i < count; i++ )
641 {
642 wxString title = wxStripMenuCodes(m_titles[i]);
643 if ( menuTitle == title )
644 return i;
645 }
646
647 return wxNOT_FOUND;
648
649 }
650
651 // ---------------------------------------------------------------------------
652 // wxMenuBar construction
653 // ---------------------------------------------------------------------------
654
655 wxMenu *wxMenuBar::Replace(size_t pos, wxMenu *menu, const wxString& title)
656 {
657 wxMenu *menuOld = wxMenuBarBase::Replace(pos, menu, title);
658 if ( !menuOld )
659 return FALSE;
660 m_titles[pos] = title;
661
662 if ( IsAttached() )
663 {
664 // can't use ModifyMenu() because it deletes the submenu it replaces
665 if ( !::RemoveMenu(GetHmenu(), (UINT)pos, MF_BYPOSITION) )
666 {
667 wxLogLastError("RemoveMenu");
668 }
669
670 if ( !::InsertMenu(GetHmenu(), (UINT)pos,
671 MF_BYPOSITION | MF_POPUP | MF_STRING,
672 (UINT)GetHmenuOf(menu), title) )
673 {
674 wxLogLastError("InsertMenu");
675 }
676
677 #if wxUSE_ACCEL
678 if ( menuOld->HasAccels() || menu->HasAccels() )
679 {
680 // need to rebuild accell table
681 RebuildAccelTable();
682 }
683 #endif // wxUSE_ACCEL
684
685 Refresh();
686 }
687
688 return menuOld;
689 }
690
691 bool wxMenuBar::Insert(size_t pos, wxMenu *menu, const wxString& title)
692 {
693 if ( !wxMenuBarBase::Insert(pos, menu, title) )
694 return FALSE;
695
696 m_titles.Insert(title, pos);
697
698 menu->Attach(this);
699
700 if ( IsAttached() )
701 {
702 if ( !::InsertMenu(GetHmenu(), pos,
703 MF_BYPOSITION | MF_POPUP | MF_STRING,
704 (UINT)GetHmenuOf(menu), title) )
705 {
706 wxLogLastError("InsertMenu");
707 }
708
709 #if wxUSE_ACCEL
710 if ( menu->HasAccels() )
711 {
712 // need to rebuild accell table
713 RebuildAccelTable();
714 }
715 #endif // wxUSE_ACCEL
716
717 Refresh();
718 }
719
720 return TRUE;
721 }
722
723 bool wxMenuBar::Append(wxMenu *menu, const wxString& title)
724 {
725 WXHMENU submenu = menu ? menu->GetHMenu() : 0;
726 wxCHECK_MSG( submenu, FALSE, wxT("can't append invalid menu to menubar") );
727
728 if ( !wxMenuBarBase::Append(menu, title) )
729 return FALSE;
730
731 menu->Attach(this);
732
733 m_titles.Add(title);
734
735 if ( IsAttached() )
736 {
737 if ( !::AppendMenu(GetHmenu(), MF_POPUP | MF_STRING,
738 (UINT)submenu, title) )
739 {
740 wxLogLastError(wxT("AppendMenu"));
741 }
742
743 #if wxUSE_ACCEL
744 if ( menu->HasAccels() )
745 {
746 // need to rebuild accell table
747 RebuildAccelTable();
748 }
749 #endif // wxUSE_ACCEL
750
751 Refresh();
752 }
753
754 return TRUE;
755 }
756
757 wxMenu *wxMenuBar::Remove(size_t pos)
758 {
759 wxMenu *menu = wxMenuBarBase::Remove(pos);
760 if ( !menu )
761 return NULL;
762
763 if ( IsAttached() )
764 {
765 if ( !::RemoveMenu(GetHmenu(), (UINT)pos, MF_BYPOSITION) )
766 {
767 wxLogLastError("RemoveMenu");
768 }
769
770 menu->Detach();
771
772 #if wxUSE_ACCEL
773 if ( menu->HasAccels() )
774 {
775 // need to rebuild accell table
776 RebuildAccelTable();
777 }
778 #endif // wxUSE_ACCEL
779
780 Refresh();
781 }
782
783 m_titles.Remove(pos);
784
785 return menu;
786 }
787
788 #if wxUSE_ACCEL
789
790 void wxMenuBar::RebuildAccelTable()
791 {
792 // merge the accelerators of all menus into one accel table
793 size_t nAccelCount = 0;
794 size_t i, count = GetMenuCount();
795 for ( i = 0; i < count; i++ )
796 {
797 nAccelCount += m_menus[i]->GetAccelCount();
798 }
799
800 if ( nAccelCount )
801 {
802 wxAcceleratorEntry *accelEntries = new wxAcceleratorEntry[nAccelCount];
803
804 nAccelCount = 0;
805 for ( i = 0; i < count; i++ )
806 {
807 nAccelCount += m_menus[i]->CopyAccels(&accelEntries[nAccelCount]);
808 }
809
810 m_accelTable = wxAcceleratorTable(nAccelCount, accelEntries);
811
812 delete [] accelEntries;
813 }
814 }
815
816 #endif // wxUSE_ACCEL
817
818 void wxMenuBar::Attach(wxFrame *frame)
819 {
820 // wxASSERT_MSG( !IsAttached(), wxT("menubar already attached!") );
821
822 m_menuBarFrame = frame;
823
824 #if wxUSE_ACCEL
825 RebuildAccelTable();
826 #endif // wxUSE_ACCEL
827 }
828
829 void wxMenuBar::Detach()
830 {
831 // ::DestroyMenu((HMENU)m_hMenu);
832 m_hMenu = (WXHMENU)NULL;
833 m_menuBarFrame = NULL;
834 }
835
836
837 // ---------------------------------------------------------------------------
838 // wxMenuBar searching for menu items
839 // ---------------------------------------------------------------------------
840
841 // Find the itemString in menuString, and return the item id or wxNOT_FOUND
842 int wxMenuBar::FindMenuItem(const wxString& menuString,
843 const wxString& itemString) const
844 {
845 wxString menuLabel = wxStripMenuCodes(menuString);
846 size_t count = GetMenuCount();
847 for ( size_t i = 0; i < count; i++ )
848 {
849 wxString title = wxStripMenuCodes(m_titles[i]);
850 if ( menuString == title )
851 return m_menus[i]->FindItem(itemString);
852 }
853
854 return wxNOT_FOUND;
855 }
856
857 wxMenuItem *wxMenuBar::FindItem(int id, wxMenu **itemMenu) const
858 {
859 if ( itemMenu )
860 *itemMenu = NULL;
861
862 wxMenuItem *item = NULL;
863 size_t count = GetMenuCount();
864 for ( size_t i = 0; !item && (i < count); i++ )
865 {
866 item = m_menus[i]->FindItem(id, itemMenu);
867 }
868
869 return item;
870 }
871