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