]> git.saurik.com Git - wxWidgets.git/blame - src/common/menucmn.cpp
applied the patch from Dimitri to prevent crashes with (some) interlaced GIFs
[wxWidgets.git] / src / common / menucmn.cpp
CommitLineData
3dfac970
VZ
1///////////////////////////////////////////////////////////////////////////////
2// Name: common/menucmn.cpp
3// Purpose: wxMenu and wxMenuBar methods common to all ports
4// Author: Vadim Zeitlin
5// Modified by:
6// Created: 26.10.99
7// RCS-ID: $Id$
8// Copyright: (c) wxWindows team
9// Licence: wxWindows license
10///////////////////////////////////////////////////////////////////////////////
11
12// ============================================================================
13// declarations
14// ============================================================================
15
16// ----------------------------------------------------------------------------
17// headers
18// ----------------------------------------------------------------------------
19
20#ifdef __GNUG__
21 #pragma implementation "menubase.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
1e6feb95
VZ
31#if wxUSE_MENUS
32
33#include <ctype.h>
34
3dfac970 35#ifndef WX_PRECOMP
1e6feb95
VZ
36 #include "wx/intl.h"
37 #include "wx/log.h"
3dfac970
VZ
38 #include "wx/menu.h"
39#endif
40
41// ----------------------------------------------------------------------------
42// template lists
43// ----------------------------------------------------------------------------
44
45#include "wx/listimpl.cpp"
717a57c2 46
3dfac970 47WX_DEFINE_LIST(wxMenuList);
717a57c2 48WX_DEFINE_LIST(wxMenuItemList);
3dfac970
VZ
49
50// ============================================================================
51// implementation
52// ============================================================================
53
54// ----------------------------------------------------------------------------
717a57c2
VZ
55// wxMenuItem
56// ----------------------------------------------------------------------------
57
58wxMenuItemBase::~wxMenuItemBase()
59{
1e6feb95 60 delete m_subMenu;
717a57c2
VZ
61}
62
63#if wxUSE_ACCEL
64
1e6feb95
VZ
65// return wxAcceleratorEntry for the given menu string or NULL if none
66// specified
67wxAcceleratorEntry *wxGetAccelFromString(const wxString& label)
68{
69 // check for accelerators: they are given after '\t'
70 int posTab = label.Find(wxT('\t'));
71 if ( posTab != wxNOT_FOUND ) {
72 // parse the accelerator string
73 int keyCode = 0;
74 int accelFlags = wxACCEL_NORMAL;
75 wxString current;
76 for ( size_t n = (size_t)posTab + 1; n < label.Len(); n++ ) {
77 if ( (label[n] == '+') || (label[n] == '-') ) {
78 if ( current == _("ctrl") )
79 accelFlags |= wxACCEL_CTRL;
80 else if ( current == _("alt") )
81 accelFlags |= wxACCEL_ALT;
82 else if ( current == _("shift") )
83 accelFlags |= wxACCEL_SHIFT;
84 else {
a070d8ce
VZ
85 // we may have "Ctrl-+", for example, but we still want to
86 // catch typos like "Crtl-A" so only give the warning if we
87 // have something before the current '+' or '-', else take
88 // it as a literal symbol
89 if ( current.empty() )
90 {
91 current += label[n];
92
93 // skip clearing it below
94 continue;
95 }
96 else
97 {
98 wxLogDebug(wxT("Unknown accel modifier: '%s'"),
99 current.c_str());
100 }
1e6feb95
VZ
101 }
102
a070d8ce 103 current.clear();
1e6feb95
VZ
104 }
105 else {
106 current += wxTolower(label[n]);
107 }
108 }
109
110 if ( current.IsEmpty() ) {
111 wxLogDebug(wxT("No accel key found, accel string ignored."));
112 }
113 else {
114 if ( current.Len() == 1 ) {
115 // it's a letter
116 keyCode = wxToupper(current[0U]);
117 }
118 else {
119 // is it a function key?
120 if ( current[0U] == 'f' && isdigit(current[1U]) &&
121 (current.Len() == 2 ||
122 (current.Len() == 3 && isdigit(current[2U]))) ) {
123 int n;
124 wxSscanf(current.c_str() + 1, wxT("%d"), &n);
125
126 keyCode = WXK_F1 + n - 1;
127 }
128 else {
129 // several special cases
130 current.MakeUpper();
131 if ( current == wxT("DEL") ) {
132 keyCode = WXK_DELETE;
133 }
134 else if ( current == wxT("DELETE") ) {
135 keyCode = WXK_DELETE;
136 }
137 else if ( current == wxT("INS") ) {
138 keyCode = WXK_INSERT;
139 }
140 else if ( current == wxT("INSERT") ) {
141 keyCode = WXK_INSERT;
142 }
143#if 0
144 else if ( current == wxT("PGUP") ) {
145 keyCode = VK_PRIOR;
146 }
147 else if ( current == wxT("PGDN") ) {
148 keyCode = VK_NEXT;
149 }
150#endif
151 else
152 {
153 wxLogDebug(wxT("Unrecognized accel key '%s', accel string ignored."),
154 current.c_str());
155 }
156 }
157 }
158 }
159
160 if ( keyCode ) {
161 // we do have something
162 return new wxAcceleratorEntry(accelFlags, keyCode);
163 }
164 }
165
166 return (wxAcceleratorEntry *)NULL;
167}
168
169wxAcceleratorEntry *wxMenuItemBase::GetAccel() const
170{
171 return wxGetAccelFromString(GetText());
172}
173
717a57c2
VZ
174void wxMenuItemBase::SetAccel(wxAcceleratorEntry *accel)
175{
176 wxString text = m_text.BeforeFirst(wxT('\t'));
177 if ( accel )
178 {
179 text += wxT('\t');
180
181 int flags = accel->GetFlags();
182 if ( flags & wxACCEL_ALT )
183 text += wxT("Alt-");
184 if ( flags & wxACCEL_CTRL )
185 text += wxT("Ctrl-");
186 if ( flags & wxACCEL_SHIFT )
187 text += wxT("Shift-");
188
189 int code = accel->GetKeyCode();
190 switch ( code )
191 {
192 case WXK_F1:
193 case WXK_F2:
194 case WXK_F3:
195 case WXK_F4:
196 case WXK_F5:
197 case WXK_F6:
198 case WXK_F7:
199 case WXK_F8:
200 case WXK_F9:
201 case WXK_F10:
202 case WXK_F11:
203 case WXK_F12:
204 text << wxT('F') << code - WXK_F1 + 1;
205 break;
206
207 // if there are any other keys wxGetAccelFromString() may return,
208 // we should process them here
209
210 default:
211 if ( wxIsalnum(code) )
212 {
213 text << (wxChar)code;
214
215 break;
216 }
217
218 wxFAIL_MSG( wxT("unknown keyboard accel") );
219 }
220 }
221
222 SetText(text);
223}
224
225#endif // wxUSE_ACCEL
226
227// ----------------------------------------------------------------------------
228// wxMenu ctor and dtor
229// ----------------------------------------------------------------------------
230
231void wxMenuBase::Init(long style)
232{
233 m_items.DeleteContents(TRUE);
234
235 m_menuBar = (wxMenuBar *)NULL;
236 m_menuParent = (wxMenu *)NULL;
237
238 m_invokingWindow = (wxWindow *)NULL;
239 m_style = style;
240 m_clientData = (void *)NULL;
241 m_eventHandler = this;
9739d9ee
VZ
242
243#if wxUSE_MENU_CALLBACK
5b0d48b3 244 m_callback = (wxFunction) NULL;
9739d9ee 245#endif // wxUSE_MENU_CALLBACK
717a57c2
VZ
246}
247
248wxMenuBase::~wxMenuBase()
249{
a583e623 250 // nothing to do, wxMenuItemList dtor will delete the menu items.
1e6feb95
VZ
251
252 // Actually, in GTK, the submenus have to get deleted first.
717a57c2
VZ
253}
254
255// ----------------------------------------------------------------------------
256// wxMenu item adding/removing
257// ----------------------------------------------------------------------------
258
1e6feb95
VZ
259void wxMenuBase::AddSubMenu(wxMenu *submenu)
260{
261 wxCHECK_RET( submenu, _T("can't add a NULL submenu") );
262
263 if ( m_menuBar )
264 {
265 submenu->Attach(m_menuBar);
266 }
267
268 submenu->SetParent((wxMenu *)this);
269}
270
717a57c2
VZ
271bool wxMenuBase::DoAppend(wxMenuItem *item)
272{
273 wxCHECK_MSG( item, FALSE, wxT("invalid item in wxMenu::Append()") );
274
275 m_items.Append(item);
1e6feb95
VZ
276 if ( item->IsSubMenu() )
277 {
278 AddSubMenu(item->GetSubMenu());
279 }
717a57c2
VZ
280
281 return TRUE;
282}
283
284bool wxMenuBase::Insert(size_t pos, wxMenuItem *item)
285{
286 wxCHECK_MSG( item, FALSE, wxT("invalid item in wxMenu::Insert") );
717a57c2 287
32db328c
VZ
288 if ( pos == GetMenuItemCount() )
289 {
290 return DoAppend(item);
291 }
292 else
293 {
294 wxCHECK_MSG( pos < GetMenuItemCount(), FALSE,
295 wxT("invalid index in wxMenu::Insert") );
296
297 return DoInsert(pos, item);
298 }
717a57c2
VZ
299}
300
301bool wxMenuBase::DoInsert(size_t pos, wxMenuItem *item)
302{
303 wxCHECK_MSG( item, FALSE, wxT("invalid item in wxMenu::Insert()") );
304
305 wxMenuItemList::Node *node = m_items.Item(pos);
306 wxCHECK_MSG( node, FALSE, wxT("invalid index in wxMenu::Insert()") );
307
308 m_items.Insert(node, item);
1e6feb95
VZ
309 if ( item->IsSubMenu() )
310 {
311 AddSubMenu(item->GetSubMenu());
312 }
717a57c2
VZ
313
314 return TRUE;
315}
316
317wxMenuItem *wxMenuBase::Remove(wxMenuItem *item)
318{
319 wxCHECK_MSG( item, NULL, wxT("invalid item in wxMenu::Remove") );
320
321 return DoRemove(item);
322}
323
324wxMenuItem *wxMenuBase::DoRemove(wxMenuItem *item)
325{
326 wxMenuItemList::Node *node = m_items.Find(item);
327
328 // if we get here, the item is valid or one of Remove() functions is broken
329 wxCHECK_MSG( node, NULL, wxT("bug in wxMenu::Remove logic") );
330
331 // we detach the item, but we do delete the list node (i.e. don't call
332 // DetachNode() here!)
333 node->SetData((wxMenuItem *)NULL); // to prevent it from deleting the item
334 m_items.DeleteNode(node);
335
336 // item isn't attached to anything any more
337 wxMenu *submenu = item->GetSubMenu();
338 if ( submenu )
339 {
340 submenu->SetParent((wxMenu *)NULL);
341 }
342
343 return item;
344}
345
346bool wxMenuBase::Delete(wxMenuItem *item)
347{
39d03faf 348 wxCHECK_MSG( item, FALSE, wxT("invalid item in wxMenu::Delete") );
717a57c2
VZ
349
350 return DoDelete(item);
351}
352
353bool wxMenuBase::DoDelete(wxMenuItem *item)
354{
355 wxMenuItem *item2 = DoRemove(item);
356 wxCHECK_MSG( item2, FALSE, wxT("failed to delete menu item") );
357
358 // don't delete the submenu
359 item2->SetSubMenu((wxMenu *)NULL);
360
361 delete item2;
362
363 return TRUE;
364}
365
366bool wxMenuBase::Destroy(wxMenuItem *item)
367{
39d03faf 368 wxCHECK_MSG( item, FALSE, wxT("invalid item in wxMenu::Destroy") );
717a57c2
VZ
369
370 return DoDestroy(item);
371}
372
373bool wxMenuBase::DoDestroy(wxMenuItem *item)
374{
375 wxMenuItem *item2 = DoRemove(item);
376 wxCHECK_MSG( item2, FALSE, wxT("failed to delete menu item") );
377
378 delete item2;
379
380 return TRUE;
381}
382
383// ----------------------------------------------------------------------------
384// wxMenu searching for items
385// ----------------------------------------------------------------------------
386
387// Finds the item id matching the given string, -1 if not found.
388int wxMenuBase::FindItem(const wxString& text) const
389{
3b59cdbf 390 wxString label = wxMenuItem::GetLabelFromText(text);
717a57c2
VZ
391 for ( wxMenuItemList::Node *node = m_items.GetFirst();
392 node;
393 node = node->GetNext() )
394 {
395 wxMenuItem *item = node->GetData();
396 if ( item->IsSubMenu() )
397 {
398 int rc = item->GetSubMenu()->FindItem(label);
399 if ( rc != wxNOT_FOUND )
400 return rc;
401 }
adb21613
VZ
402
403 // we execute this code for submenus as well to alllow finding them by
404 // name just like the ordinary items
405 if ( !item->IsSeparator() )
717a57c2
VZ
406 {
407 if ( item->GetLabel() == label )
408 return item->GetId();
409 }
410 }
411
412 return wxNOT_FOUND;
413}
414
415// recursive search for item by id
416wxMenuItem *wxMenuBase::FindItem(int itemId, wxMenu **itemMenu) const
417{
418 if ( itemMenu )
419 *itemMenu = NULL;
420
421 wxMenuItem *item = NULL;
422 for ( wxMenuItemList::Node *node = m_items.GetFirst();
423 node && !item;
424 node = node->GetNext() )
425 {
426 item = node->GetData();
427
428 if ( item->GetId() == itemId )
429 {
430 if ( itemMenu )
431 *itemMenu = (wxMenu *)this;
432 }
433 else if ( item->IsSubMenu() )
434 {
435 item = item->GetSubMenu()->FindItem(itemId, itemMenu);
436 }
437 else
438 {
439 // don't exit the loop
440 item = NULL;
441 }
442 }
443
444 return item;
445}
446
447// non recursive search
448wxMenuItem *wxMenuBase::FindChildItem(int id, size_t *ppos) const
449{
450 wxMenuItem *item = (wxMenuItem *)NULL;
451 wxMenuItemList::Node *node = GetMenuItems().GetFirst();
452
453 size_t pos;
454 for ( pos = 0; node; pos++ )
455 {
1dddf838
VZ
456 if ( node->GetData()->GetId() == id )
457 {
458 item = node->GetData();
459
717a57c2 460 break;
1dddf838 461 }
717a57c2
VZ
462
463 node = node->GetNext();
464 }
465
466 if ( ppos )
467 {
1987af7e 468 *ppos = item ? pos : (size_t)wxNOT_FOUND;
717a57c2
VZ
469 }
470
471 return item;
472}
473
474// ----------------------------------------------------------------------------
1e6feb95 475// wxMenu helpers used by derived classes
717a57c2
VZ
476// ----------------------------------------------------------------------------
477
478// Update a menu and all submenus recursively. source is the object that has
479// the update event handlers defined for it. If NULL, the menu or associated
480// window will be used.
481void wxMenuBase::UpdateUI(wxEvtHandler* source)
482{
483 if ( !source && GetInvokingWindow() )
484 source = GetInvokingWindow()->GetEventHandler();
485 if ( !source )
486 source = GetEventHandler();
487 if ( !source )
488 source = this;
489
490 wxMenuItemList::Node* node = GetMenuItems().GetFirst();
491 while ( node )
492 {
493 wxMenuItem* item = node->GetData();
494 if ( !item->IsSeparator() )
495 {
496 wxWindowID id = item->GetId();
497 wxUpdateUIEvent event(id);
498 event.SetEventObject( source );
499
500 if ( source->ProcessEvent(event) )
501 {
502 // if anything changed, update the chanegd attribute
503 if (event.GetSetText())
504 SetLabel(id, event.GetText());
505 if (event.GetSetChecked())
506 Check(id, event.GetChecked());
507 if (event.GetSetEnabled())
508 Enable(id, event.GetEnabled());
509 }
510
511 // recurse to the submenus
512 if ( item->GetSubMenu() )
513 item->GetSubMenu()->UpdateUI(source);
514 }
515 //else: item is a separator (which don't process update UI events)
516
517 node = node->GetNext();
518 }
519}
520
1e6feb95
VZ
521bool wxMenuBase::SendEvent(int id, int checked)
522{
523 wxCommandEvent event(wxEVT_COMMAND_MENU_SELECTED, id);
524 event.SetEventObject(this);
525 event.SetInt(checked);
526
527 bool processed = FALSE;
528
529#if wxUSE_MENU_CALLBACK
530 // Try a callback
531 if (m_callback)
532 {
533 (void)(*(m_callback))(*this, event);
534 processed = TRUE;
535 }
536#endif // wxUSE_MENU_CALLBACK
537
538 // Try the menu's event handler
539 if ( !processed )
540 {
541 wxEvtHandler *handler = GetEventHandler();
542 if ( handler )
543 processed = handler->ProcessEvent(event);
544 }
545
546 // Try the window the menu was popped up from (and up through the
547 // hierarchy)
548 if ( !processed )
549 {
550 const wxMenuBase *menu = this;
551 while ( menu )
552 {
553 wxWindow *win = menu->GetInvokingWindow();
554 if ( win )
555 {
556 processed = win->GetEventHandler()->ProcessEvent(event);
557 break;
558 }
559
560 menu = menu->GetParent();
561 }
562 }
563
564 return processed;
565}
566
567// ----------------------------------------------------------------------------
568// wxMenu attaching/detaching to/from menu bar
569// ----------------------------------------------------------------------------
570
571void wxMenuBase::Attach(wxMenuBarBase *menubar)
572{
573 // use Detach() instead!
574 wxASSERT_MSG( menubar, _T("menu can't be attached to NULL menubar") );
575
576 // use IsAttached() to prevent this from happening
577 wxASSERT_MSG( !m_menuBar, _T("attaching menu twice?") );
578
579 m_menuBar = (wxMenuBar *)menubar;
580}
581
582void wxMenuBase::Detach()
583{
584 // use IsAttached() to prevent this from happening
585 wxASSERT_MSG( m_menuBar, _T("detaching unattached menu?") );
586
587 m_menuBar = NULL;
588}
589
717a57c2
VZ
590// ----------------------------------------------------------------------------
591// wxMenu functions forwarded to wxMenuItem
592// ----------------------------------------------------------------------------
593
594void wxMenuBase::Enable( int id, bool enable )
595{
596 wxMenuItem *item = FindItem(id);
597
598 wxCHECK_RET( item, wxT("wxMenu::Enable: no such item") );
599
600 item->Enable(enable);
601}
602
603bool wxMenuBase::IsEnabled( int id ) const
604{
605 wxMenuItem *item = FindItem(id);
606
607 wxCHECK_MSG( item, FALSE, wxT("wxMenu::IsEnabled: no such item") );
608
609 return item->IsEnabled();
610}
611
612void wxMenuBase::Check( int id, bool enable )
613{
614 wxMenuItem *item = FindItem(id);
615
616 wxCHECK_RET( item, wxT("wxMenu::Check: no such item") );
617
618 item->Check(enable);
619}
620
621bool wxMenuBase::IsChecked( int id ) const
622{
623 wxMenuItem *item = FindItem(id);
624
625 wxCHECK_MSG( item, FALSE, wxT("wxMenu::IsChecked: no such item") );
626
627 return item->IsChecked();
628}
629
630void wxMenuBase::SetLabel( int id, const wxString &label )
631{
632 wxMenuItem *item = FindItem(id);
633
634 wxCHECK_RET( item, wxT("wxMenu::SetLabel: no such item") );
635
636 item->SetText(label);
637}
638
639wxString wxMenuBase::GetLabel( int id ) const
640{
641 wxMenuItem *item = FindItem(id);
642
643 wxCHECK_MSG( item, wxT(""), wxT("wxMenu::GetLabel: no such item") );
644
645 return item->GetText();
646}
647
648void wxMenuBase::SetHelpString( int id, const wxString& helpString )
649{
650 wxMenuItem *item = FindItem(id);
651
652 wxCHECK_RET( item, wxT("wxMenu::SetHelpString: no such item") );
653
654 item->SetHelp( helpString );
655}
656
657wxString wxMenuBase::GetHelpString( int id ) const
658{
659 wxMenuItem *item = FindItem(id);
660
661 wxCHECK_MSG( item, wxT(""), wxT("wxMenu::GetHelpString: no such item") );
662
663 return item->GetHelp();
664}
665
666// ----------------------------------------------------------------------------
667// wxMenuBarBase ctor and dtor
3dfac970
VZ
668// ----------------------------------------------------------------------------
669
670wxMenuBarBase::wxMenuBarBase()
671{
672 // we own the menus when we get them
673 m_menus.DeleteContents(TRUE);
1e6feb95
VZ
674
675 // not attached yet
676 m_menuBarFrame = NULL;
3dfac970
VZ
677}
678
679wxMenuBarBase::~wxMenuBarBase()
680{
681 // nothing to do, the list will delete the menus because of the call to
682 // DeleteContents() above
683}
684
685// ----------------------------------------------------------------------------
686// wxMenuBar item access: the base class versions manage m_menus list, the
687// derived class should reflect the changes in the real menubar
688// ----------------------------------------------------------------------------
689
690wxMenu *wxMenuBarBase::GetMenu(size_t pos) const
691{
692 wxMenuList::Node *node = m_menus.Item(pos);
693 wxCHECK_MSG( node, NULL, wxT("bad index in wxMenuBar::GetMenu()") );
694
695 return node->GetData();
696}
697
698bool wxMenuBarBase::Append(wxMenu *menu, const wxString& WXUNUSED(title))
699{
700 wxCHECK_MSG( menu, FALSE, wxT("can't append NULL menu") );
701
702 m_menus.Append(menu);
1e6feb95 703 menu->Attach(this);
3dfac970
VZ
704
705 return TRUE;
706}
707
708bool wxMenuBarBase::Insert(size_t pos, wxMenu *menu,
32db328c 709 const wxString& title)
3dfac970 710{
32db328c
VZ
711 if ( pos == m_menus.GetCount() )
712 {
186baeb2 713 return wxMenuBarBase::Append(menu, title);
32db328c 714 }
1e6feb95 715 else // not at the end
32db328c
VZ
716 {
717 wxCHECK_MSG( menu, FALSE, wxT("can't insert NULL menu") );
3dfac970 718
32db328c
VZ
719 wxMenuList::Node *node = m_menus.Item(pos);
720 wxCHECK_MSG( node, FALSE, wxT("bad index in wxMenuBar::Insert()") );
3dfac970 721
32db328c 722 m_menus.Insert(node, menu);
1e6feb95 723 menu->Attach(this);
3dfac970 724
32db328c
VZ
725 return TRUE;
726 }
3dfac970
VZ
727}
728
729wxMenu *wxMenuBarBase::Replace(size_t pos, wxMenu *menu,
730 const wxString& WXUNUSED(title))
731{
732 wxCHECK_MSG( menu, NULL, wxT("can't insert NULL menu") );
733
734 wxMenuList::Node *node = m_menus.Item(pos);
735 wxCHECK_MSG( node, NULL, wxT("bad index in wxMenuBar::Replace()") );
736
737 wxMenu *menuOld = node->GetData();
738 node->SetData(menu);
739
1e6feb95
VZ
740 menu->Attach(this);
741 menuOld->Detach();
742
3dfac970
VZ
743 return menuOld;
744}
745
746wxMenu *wxMenuBarBase::Remove(size_t pos)
747{
748 wxMenuList::Node *node = m_menus.Item(pos);
749 wxCHECK_MSG( node, NULL, wxT("bad index in wxMenuBar::Remove()") );
750
751 node = m_menus.DetachNode(node);
752 wxCHECK( node, NULL ); // unexpected
753 wxMenu *menu = node->GetData();
1e6feb95 754 menu->Detach();
3dfac970
VZ
755
756 delete node;
757
758 return menu;
759}
760
270e8b6a 761int wxMenuBarBase::FindMenu(const wxString& title) const
52130557
VZ
762{
763 wxString label = wxMenuItem::GetLabelFromText(title);
764
765 size_t count = GetMenuCount();
766 for ( size_t i = 0; i < count; i++ )
767 {
768 wxString title2 = GetLabelTop(i);
769 if ( (title2 == title) ||
770 (wxMenuItem::GetLabelFromText(title2) == label) )
771 {
772 // found
773 return (int)i;
774 }
775 }
776
777 return wxNOT_FOUND;
778
779}
780
1e6feb95
VZ
781// ----------------------------------------------------------------------------
782// wxMenuBar attaching/detaching to/from the frame
783// ----------------------------------------------------------------------------
784
785void wxMenuBarBase::Attach(wxFrame *frame)
786{
787 wxASSERT_MSG( !IsAttached(), wxT("menubar already attached!") );
788
789 m_menuBarFrame = frame;
790}
791
792void wxMenuBarBase::Detach()
793{
794 wxASSERT_MSG( IsAttached(), wxT("detaching unattached menubar") );
795
796 m_menuBarFrame = NULL;
797}
798
799// ----------------------------------------------------------------------------
800// wxMenuBar searching for items
801// ----------------------------------------------------------------------------
802
803wxMenuItem *wxMenuBarBase::FindItem(int id, wxMenu **menu) const
804{
805 if ( menu )
806 *menu = NULL;
807
808 wxMenuItem *item = NULL;
809 size_t count = GetMenuCount();
810 for ( size_t i = 0; !item && (i < count); i++ )
811 {
812 item = m_menus[i]->FindItem(id, menu);
813 }
814
815 return item;
816}
817
818int wxMenuBarBase::FindMenuItem(const wxString& menu, const wxString& item) const
819{
820 wxString label = wxMenuItem::GetLabelFromText(menu);
821
822 int i = 0;
823 wxMenuList::Node *node;
824 for ( node = m_menus.GetFirst(); node; node = node->GetNext(), i++ )
825 {
826 if ( label == wxMenuItem::GetLabelFromText(GetLabelTop(i)) )
827 return node->GetData()->FindItem(item);
828 }
829
830 return wxNOT_FOUND;
831}
832
3dfac970
VZ
833// ---------------------------------------------------------------------------
834// wxMenuBar functions forwarded to wxMenuItem
835// ---------------------------------------------------------------------------
836
837void wxMenuBarBase::Enable(int id, bool enable)
838{
839 wxMenuItem *item = FindItem(id);
840
841 wxCHECK_RET( item, wxT("attempt to enable an item which doesn't exist") );
842
843 item->Enable(enable);
844}
845
846void wxMenuBarBase::Check(int id, bool check)
847{
848 wxMenuItem *item = FindItem(id);
849
850 wxCHECK_RET( item, wxT("attempt to check an item which doesn't exist") );
851 wxCHECK_RET( item->IsCheckable(), wxT("attempt to check an uncheckable item") );
852
853 item->Check(check);
854}
855
856bool wxMenuBarBase::IsChecked(int id) const
857{
858 wxMenuItem *item = FindItem(id);
859
860 wxCHECK_MSG( item, FALSE, wxT("wxMenuBar::IsChecked(): no such item") );
861
862 return item->IsChecked();
863}
864
865bool wxMenuBarBase::IsEnabled(int id) const
866{
867 wxMenuItem *item = FindItem(id);
868
869 wxCHECK_MSG( item, FALSE, wxT("wxMenuBar::IsEnabled(): no such item") );
870
871 return item->IsEnabled();
872}
873
874void wxMenuBarBase::SetLabel(int id, const wxString& label)
875{
876 wxMenuItem *item = FindItem(id);
877
878 wxCHECK_RET( item, wxT("wxMenuBar::SetLabel(): no such item") );
879
880 item->SetText(label);
881}
882
883wxString wxMenuBarBase::GetLabel(int id) const
884{
885 wxMenuItem *item = FindItem(id);
886
887 wxCHECK_MSG( item, wxEmptyString,
888 wxT("wxMenuBar::GetLabel(): no such item") );
889
890 return item->GetText();
891}
892
893void wxMenuBarBase::SetHelpString(int id, const wxString& helpString)
894{
895 wxMenuItem *item = FindItem(id);
896
897 wxCHECK_RET( item, wxT("wxMenuBar::SetHelpString(): no such item") );
898
899 item->SetHelp(helpString);
900}
901
902wxString wxMenuBarBase::GetHelpString(int id) const
903{
904 wxMenuItem *item = FindItem(id);
905
906 wxCHECK_MSG( item, wxEmptyString,
907 wxT("wxMenuBar::GetHelpString(): no such item") );
908
909 return item->GetHelp();
910}
911
1e6feb95 912#endif // wxUSE_MENUS