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