1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: src/common/menucmn.cpp
3 // Purpose: wxMenu and wxMenuBar methods common to all ports
4 // Author: Vadim Zeitlin
8 // Copyright: (c) wxWidgets team
9 // Licence: wxWindows licence
10 ///////////////////////////////////////////////////////////////////////////////
12 // ============================================================================
14 // ============================================================================
16 // ----------------------------------------------------------------------------
18 // ----------------------------------------------------------------------------
20 // For compilers that support precompilation, includes "wx.h".
21 #include "wx/wxprec.h"
37 #include "wx/stockitem.h"
39 // ----------------------------------------------------------------------------
41 // ----------------------------------------------------------------------------
43 #include "wx/listimpl.cpp"
45 WX_DEFINE_LIST(wxMenuList
)
46 WX_DEFINE_LIST(wxMenuItemList
)
48 // ============================================================================
50 // ============================================================================
52 // ----------------------------------------------------------------------------
54 // ----------------------------------------------------------------------------
59 static const struct wxKeyName
65 { WXK_DELETE
, wxTRANSLATE("DEL") },
66 { WXK_DELETE
, wxTRANSLATE("DELETE") },
67 { WXK_BACK
, wxTRANSLATE("BACK") },
68 { WXK_INSERT
, wxTRANSLATE("INS") },
69 { WXK_INSERT
, wxTRANSLATE("INSERT") },
70 { WXK_RETURN
, wxTRANSLATE("ENTER") },
71 { WXK_RETURN
, wxTRANSLATE("RETURN") },
72 { WXK_PAGEUP
, wxTRANSLATE("PGUP") },
73 { WXK_PAGEDOWN
, wxTRANSLATE("PGDN") },
74 { WXK_LEFT
, wxTRANSLATE("LEFT") },
75 { WXK_RIGHT
, wxTRANSLATE("RIGHT") },
76 { WXK_UP
, wxTRANSLATE("UP") },
77 { WXK_DOWN
, wxTRANSLATE("DOWN") },
78 { WXK_HOME
, wxTRANSLATE("HOME") },
79 { WXK_END
, wxTRANSLATE("END") },
80 { WXK_SPACE
, wxTRANSLATE("SPACE") },
81 { WXK_TAB
, wxTRANSLATE("TAB") },
82 { WXK_ESCAPE
, wxTRANSLATE("ESC") },
83 { WXK_ESCAPE
, wxTRANSLATE("ESCAPE") },
84 { WXK_CANCEL
, wxTRANSLATE("CANCEL") },
85 { WXK_CLEAR
, wxTRANSLATE("CLEAR") },
86 { WXK_MENU
, wxTRANSLATE("MENU") },
87 { WXK_PAUSE
, wxTRANSLATE("PAUSE") },
88 { WXK_CAPITAL
, wxTRANSLATE("CAPITAL") },
89 { WXK_SELECT
, wxTRANSLATE("SELECT") },
90 { WXK_PRINT
, wxTRANSLATE("PRINT") },
91 { WXK_EXECUTE
, wxTRANSLATE("EXECUTE") },
92 { WXK_SNAPSHOT
, wxTRANSLATE("SNAPSHOT") },
93 { WXK_HELP
, wxTRANSLATE("HELP") },
94 { WXK_ADD
, wxTRANSLATE("ADD") },
95 { WXK_SEPARATOR
, wxTRANSLATE("SEPARATOR") },
96 { WXK_SUBTRACT
, wxTRANSLATE("SUBTRACT") },
97 { WXK_DECIMAL
, wxTRANSLATE("DECIMAL") },
98 { WXK_DIVIDE
, wxTRANSLATE("DIVIDE") },
99 { WXK_NUMLOCK
, wxTRANSLATE("NUM_LOCK") },
100 { WXK_SCROLL
, wxTRANSLATE("SCROLL_LOCK") },
101 { WXK_PAGEUP
, wxTRANSLATE("PAGEUP") },
102 { WXK_PAGEDOWN
, wxTRANSLATE("PAGEDOWN") },
103 { WXK_NUMPAD_SPACE
, wxTRANSLATE("KP_SPACE") },
104 { WXK_NUMPAD_TAB
, wxTRANSLATE("KP_TAB") },
105 { WXK_NUMPAD_ENTER
, wxTRANSLATE("KP_ENTER") },
106 { WXK_NUMPAD_HOME
, wxTRANSLATE("KP_HOME") },
107 { WXK_NUMPAD_LEFT
, wxTRANSLATE("KP_LEFT") },
108 { WXK_NUMPAD_UP
, wxTRANSLATE("KP_UP") },
109 { WXK_NUMPAD_RIGHT
, wxTRANSLATE("KP_RIGHT") },
110 { WXK_NUMPAD_DOWN
, wxTRANSLATE("KP_DOWN") },
111 { WXK_NUMPAD_PAGEUP
, wxTRANSLATE("KP_PRIOR") },
112 { WXK_NUMPAD_PAGEUP
, wxTRANSLATE("KP_PAGEUP") },
113 { WXK_NUMPAD_PAGEDOWN
, wxTRANSLATE("KP_NEXT") },
114 { WXK_NUMPAD_PAGEDOWN
, wxTRANSLATE("KP_PAGEDOWN") },
115 { WXK_NUMPAD_END
, wxTRANSLATE("KP_END") },
116 { WXK_NUMPAD_BEGIN
, wxTRANSLATE("KP_BEGIN") },
117 { WXK_NUMPAD_INSERT
, wxTRANSLATE("KP_INSERT") },
118 { WXK_NUMPAD_DELETE
, wxTRANSLATE("KP_DELETE") },
119 { WXK_NUMPAD_EQUAL
, wxTRANSLATE("KP_EQUAL") },
120 { WXK_NUMPAD_MULTIPLY
, wxTRANSLATE("KP_MULTIPLY") },
121 { WXK_NUMPAD_ADD
, wxTRANSLATE("KP_ADD") },
122 { WXK_NUMPAD_SEPARATOR
, wxTRANSLATE("KP_SEPARATOR") },
123 { WXK_NUMPAD_SUBTRACT
, wxTRANSLATE("KP_SUBTRACT") },
124 { WXK_NUMPAD_DECIMAL
, wxTRANSLATE("KP_DECIMAL") },
125 { WXK_NUMPAD_DIVIDE
, wxTRANSLATE("KP_DIVIDE") },
126 { WXK_WINDOWS_LEFT
, wxTRANSLATE("WINDOWS_LEFT") },
127 { WXK_WINDOWS_RIGHT
, wxTRANSLATE("WINDOWS_RIGHT") },
128 { WXK_WINDOWS_MENU
, wxTRANSLATE("WINDOWS_MENU") },
129 { WXK_COMMAND
, wxTRANSLATE("COMMAND") },
132 // return true if the 2 strings refer to the same accel
134 // as accels can be either translated or not, check for both possibilities and
135 // also compare case-insensitively as the key names case doesn't count
136 static inline bool CompareAccelString(const wxString
& str
, const wxChar
*accel
)
138 return str
.CmpNoCase(accel
) == 0
140 || str
.CmpNoCase(wxGetTranslation(accel
)) == 0
145 // return prefixCode+number if the string is of the form "<prefix><number>" and
148 // first and last parameter specify the valid domain for "number" part
150 IsNumberedAccelKey(const wxString
& str
,
151 const wxChar
*prefix
,
152 wxKeyCode prefixCode
,
156 const size_t lenPrefix
= wxStrlen(prefix
);
157 if ( !CompareAccelString(str
.Left(lenPrefix
), prefix
) )
161 if ( !str
.Mid(lenPrefix
).ToULong(&num
) )
164 if ( num
< first
|| num
> last
)
166 // this must be a mistake, chances that this is a valid name of another
167 // key are vanishingly small
168 wxLogDebug(_T("Invalid key string \"%s\""), str
.c_str());
172 return prefixCode
+ num
- first
;
177 wxAcceleratorEntry::ParseAccel(const wxString
& text
, int *flagsOut
, int *keyOut
)
179 // the parser won't like trailing spaces
180 wxString label
= text
;
181 label
.Trim(true); // the initial \t must be preserved so don't strip leading whitespaces
183 // check for accelerators: they are given after '\t'
184 int posTab
= label
.Find(wxT('\t'));
185 if ( posTab
== wxNOT_FOUND
)
187 wxLogDebug(wxT("Invalid menu label: no accelerators"));
191 // parse the accelerator string
192 int accelFlags
= wxACCEL_NORMAL
;
194 for ( size_t n
= (size_t)posTab
+ 1; n
< label
.length(); n
++ )
196 if ( (label
[n
] == '+') || (label
[n
] == '-') )
198 if ( CompareAccelString(current
, wxTRANSLATE("ctrl")) )
199 accelFlags
|= wxACCEL_CTRL
;
200 else if ( CompareAccelString(current
, wxTRANSLATE("alt")) )
201 accelFlags
|= wxACCEL_ALT
;
202 else if ( CompareAccelString(current
, wxTRANSLATE("shift")) )
203 accelFlags
|= wxACCEL_SHIFT
;
204 else // not a recognized modifier name
206 // we may have "Ctrl-+", for example, but we still want to
207 // catch typos like "Crtl-A" so only give the warning if we
208 // have something before the current '+' or '-', else take
209 // it as a literal symbol
210 if ( current
.empty() )
214 // skip clearing it below
219 wxLogDebug(wxT("Unknown accel modifier: '%s'"),
226 else // not special character
228 current
+= (wxChar
) wxTolower(label
[n
]);
233 const size_t len
= current
.length();
237 wxLogDebug(wxT("No accel key found, accel string ignored."));
241 // it's just a letter
242 keyCode
= current
[0U];
244 // if the key is used with any modifiers, make it an uppercase one
245 // because Ctrl-A and Ctrl-a are the same; but keep it as is if it's
246 // used alone as 'a' and 'A' are different
247 if ( accelFlags
!= wxACCEL_NORMAL
)
248 keyCode
= wxToupper(keyCode
);
252 keyCode
= IsNumberedAccelKey(current
, wxTRANSLATE("F"),
256 for ( size_t n
= 0; n
< WXSIZEOF(wxKeyNames
); n
++ )
258 const wxKeyName
& kn
= wxKeyNames
[n
];
259 if ( CompareAccelString(current
, kn
.name
) )
268 keyCode
= IsNumberedAccelKey(current
, wxTRANSLATE("KP_"),
271 keyCode
= IsNumberedAccelKey(current
, wxTRANSLATE("SPECIAL"),
272 WXK_SPECIAL1
, 1, 20);
276 wxLogDebug(wxT("Unrecognized accel key '%s', accel string ignored."),
283 wxASSERT_MSG( keyCode
, _T("logic error: should have key code here") );
286 *flagsOut
= accelFlags
;
294 wxAcceleratorEntry
*wxAcceleratorEntry::Create(const wxString
& str
)
298 if ( !ParseAccel(str
, &flags
, &keyCode
) )
301 return new wxAcceleratorEntry(flags
, keyCode
);
304 bool wxAcceleratorEntry::FromString(const wxString
& str
)
306 return ParseAccel(str
, &m_flags
, &m_keyCode
);
309 wxString
wxAcceleratorEntry::ToString() const
313 int flags
= GetFlags();
314 if ( flags
& wxACCEL_ALT
)
316 if ( flags
& wxACCEL_CTRL
)
318 if ( flags
& wxACCEL_SHIFT
)
321 const int code
= GetKeyCode();
323 if ( wxIsalnum(code
) )
324 text
<< (wxChar
)code
;
325 else if ( code
>= WXK_F1
&& code
<= WXK_F12
)
326 text
<< _("F") << code
- WXK_F1
+ 1;
327 else if ( code
>= WXK_NUMPAD0
&& code
<= WXK_NUMPAD9
)
328 text
<< _("KP_") << code
- WXK_NUMPAD0
;
329 else if ( code
>= WXK_SPECIAL1
&& code
<= WXK_SPECIAL20
)
330 text
<< _("SPECIAL") << code
- WXK_SPECIAL1
+ 1;
331 else // check the named keys
334 for ( n
= 0; n
< WXSIZEOF(wxKeyNames
); n
++ )
336 const wxKeyName
& kn
= wxKeyNames
[n
];
337 if ( code
== kn
.code
)
339 text
<< wxGetTranslation(kn
.name
);
344 wxASSERT_MSG( n
!= WXSIZEOF(wxKeyNames
),
345 wxT("unknown keyboard accelerator code") );
351 wxAcceleratorEntry
*wxGetAccelFromString(const wxString
& label
)
353 return wxAcceleratorEntry::Create(label
);
356 #endif // wxUSE_ACCEL
359 // ----------------------------------------------------------------------------
361 // ----------------------------------------------------------------------------
363 wxMenuItemBase::wxMenuItemBase(wxMenu
*parentMenu
,
365 const wxString
& text
,
366 const wxString
& help
,
370 wxASSERT_MSG( parentMenu
!= NULL
, wxT("menuitem should have a menu") );
372 m_parentMenu
= parentMenu
;
378 if (m_id
== wxID_ANY
)
380 if (m_id
== wxID_SEPARATOR
)
381 m_kind
= wxITEM_SEPARATOR
;
387 wxMenuItemBase::~wxMenuItemBase()
394 wxAcceleratorEntry
*wxMenuItemBase::GetAccel() const
396 return wxAcceleratorEntry::Create(GetText());
399 void wxMenuItemBase::SetAccel(wxAcceleratorEntry
*accel
)
401 wxString text
= m_text
.BeforeFirst(wxT('\t'));
405 text
+= accel
->ToString();
411 #endif // wxUSE_ACCEL
413 void wxMenuItemBase::SetText(const wxString
& str
)
417 if ( m_text
.empty() && !IsSeparator() )
419 wxASSERT_MSG( wxIsStockID(GetId()),
420 wxT("A non-stock menu item with an empty label?") );
421 m_text
= wxGetStockLabel(GetId(), wxSTOCK_WITH_ACCELERATOR
|
422 wxSTOCK_WITH_MNEMONIC
);
426 void wxMenuItemBase::SetHelp(const wxString
& str
)
430 if ( m_help
.empty() && !IsSeparator() && wxIsStockID(GetId()) )
432 // get a stock help string
433 m_help
= wxGetStockHelpString(GetId());
437 bool wxMenuBase::ms_locked
= true;
439 // ----------------------------------------------------------------------------
440 // wxMenu ctor and dtor
441 // ----------------------------------------------------------------------------
443 void wxMenuBase::Init(long style
)
445 m_menuBar
= (wxMenuBar
*)NULL
;
446 m_menuParent
= (wxMenu
*)NULL
;
448 m_invokingWindow
= (wxWindow
*)NULL
;
450 m_clientData
= (void *)NULL
;
451 m_eventHandler
= this;
454 wxMenuBase::~wxMenuBase()
456 WX_CLEAR_LIST(wxMenuItemList
, m_items
);
458 // Actually, in GTK, the submenus have to get deleted first.
461 // ----------------------------------------------------------------------------
462 // wxMenu item adding/removing
463 // ----------------------------------------------------------------------------
465 void wxMenuBase::AddSubMenu(wxMenu
*submenu
)
467 wxCHECK_RET( submenu
, _T("can't add a NULL submenu") );
469 submenu
->SetParent((wxMenu
*)this);
472 wxMenuItem
* wxMenuBase::DoAppend(wxMenuItem
*item
)
474 wxCHECK_MSG( item
, NULL
, wxT("invalid item in wxMenu::Append()") );
476 m_items
.Append(item
);
477 item
->SetMenu((wxMenu
*)this);
478 if ( item
->IsSubMenu() )
480 AddSubMenu(item
->GetSubMenu());
486 wxMenuItem
* wxMenuBase::Insert(size_t pos
, wxMenuItem
*item
)
488 wxCHECK_MSG( item
, NULL
, wxT("invalid item in wxMenu::Insert") );
490 if ( pos
== GetMenuItemCount() )
492 return DoAppend(item
);
496 wxCHECK_MSG( pos
< GetMenuItemCount(), NULL
,
497 wxT("invalid index in wxMenu::Insert") );
499 return DoInsert(pos
, item
);
503 wxMenuItem
* wxMenuBase::DoInsert(size_t pos
, wxMenuItem
*item
)
505 wxCHECK_MSG( item
, NULL
, wxT("invalid item in wxMenu::Insert()") );
507 wxMenuItemList::compatibility_iterator node
= m_items
.Item(pos
);
508 wxCHECK_MSG( node
, NULL
, wxT("invalid index in wxMenu::Insert()") );
510 m_items
.Insert(node
, item
);
511 item
->SetMenu((wxMenu
*)this);
512 if ( item
->IsSubMenu() )
514 AddSubMenu(item
->GetSubMenu());
520 wxMenuItem
*wxMenuBase::Remove(wxMenuItem
*item
)
522 wxCHECK_MSG( item
, NULL
, wxT("invalid item in wxMenu::Remove") );
524 return DoRemove(item
);
527 wxMenuItem
*wxMenuBase::DoRemove(wxMenuItem
*item
)
529 wxMenuItemList::compatibility_iterator node
= m_items
.Find(item
);
531 // if we get here, the item is valid or one of Remove() functions is broken
532 wxCHECK_MSG( node
, NULL
, wxT("bug in wxMenu::Remove logic") );
534 // we detach the item, but we do delete the list node (i.e. don't call
535 // DetachNode() here!)
538 // item isn't attached to anything any more
539 item
->SetMenu((wxMenu
*)NULL
);
540 wxMenu
*submenu
= item
->GetSubMenu();
543 submenu
->SetParent((wxMenu
*)NULL
);
544 if ( submenu
->IsAttached() )
551 bool wxMenuBase::Delete(wxMenuItem
*item
)
553 wxCHECK_MSG( item
, false, wxT("invalid item in wxMenu::Delete") );
555 return DoDelete(item
);
558 bool wxMenuBase::DoDelete(wxMenuItem
*item
)
560 wxMenuItem
*item2
= DoRemove(item
);
561 wxCHECK_MSG( item2
, false, wxT("failed to delete menu item") );
563 // don't delete the submenu
564 item2
->SetSubMenu((wxMenu
*)NULL
);
571 bool wxMenuBase::Destroy(wxMenuItem
*item
)
573 wxCHECK_MSG( item
, false, wxT("invalid item in wxMenu::Destroy") );
575 return DoDestroy(item
);
578 bool wxMenuBase::DoDestroy(wxMenuItem
*item
)
580 wxMenuItem
*item2
= DoRemove(item
);
581 wxCHECK_MSG( item2
, false, wxT("failed to delete menu item") );
588 // ----------------------------------------------------------------------------
589 // wxMenu searching for items
590 // ----------------------------------------------------------------------------
592 // Finds the item id matching the given string, wxNOT_FOUND if not found.
593 int wxMenuBase::FindItem(const wxString
& text
) const
595 wxString label
= wxMenuItem::GetLabelFromText(text
);
596 for ( wxMenuItemList::compatibility_iterator node
= m_items
.GetFirst();
598 node
= node
->GetNext() )
600 wxMenuItem
*item
= node
->GetData();
601 if ( item
->IsSubMenu() )
603 int rc
= item
->GetSubMenu()->FindItem(label
);
604 if ( rc
!= wxNOT_FOUND
)
608 // we execute this code for submenus as well to alllow finding them by
609 // name just like the ordinary items
610 if ( !item
->IsSeparator() )
612 if ( item
->GetLabel() == label
)
613 return item
->GetId();
620 // recursive search for item by id
621 wxMenuItem
*wxMenuBase::FindItem(int itemId
, wxMenu
**itemMenu
) const
626 wxMenuItem
*item
= NULL
;
627 for ( wxMenuItemList::compatibility_iterator node
= m_items
.GetFirst();
629 node
= node
->GetNext() )
631 item
= node
->GetData();
633 if ( item
->GetId() == itemId
)
636 *itemMenu
= (wxMenu
*)this;
638 else if ( item
->IsSubMenu() )
640 item
= item
->GetSubMenu()->FindItem(itemId
, itemMenu
);
644 // don't exit the loop
652 // non recursive search
653 wxMenuItem
*wxMenuBase::FindChildItem(int id
, size_t *ppos
) const
655 wxMenuItem
*item
= (wxMenuItem
*)NULL
;
656 wxMenuItemList::compatibility_iterator node
= GetMenuItems().GetFirst();
659 for ( pos
= 0; node
; pos
++ )
661 if ( node
->GetData()->GetId() == id
)
663 item
= node
->GetData();
668 node
= node
->GetNext();
673 *ppos
= item
? pos
: (size_t)wxNOT_FOUND
;
680 wxMenuItem
* wxMenuBase::FindItemByPosition(size_t position
) const
682 wxCHECK_MSG( position
< m_items
.GetCount(), NULL
,
683 _T("wxMenu::FindItemByPosition(): invalid menu index") );
685 return m_items
.Item( position
)->GetData();
688 // ----------------------------------------------------------------------------
689 // wxMenu helpers used by derived classes
690 // ----------------------------------------------------------------------------
692 // Update a menu and all submenus recursively. source is the object that has
693 // the update event handlers defined for it. If NULL, the menu or associated
694 // window will be used.
695 void wxMenuBase::UpdateUI(wxEvtHandler
* source
)
697 if (GetInvokingWindow())
699 // Don't update menus if the parent
700 // frame is about to get deleted
701 wxWindow
*tlw
= wxGetTopLevelParent( GetInvokingWindow() );
702 if (tlw
&& wxPendingDelete
.Member(tlw
))
706 if ( !source
&& GetInvokingWindow() )
707 source
= GetInvokingWindow()->GetEventHandler();
709 source
= GetEventHandler();
713 wxMenuItemList::compatibility_iterator node
= GetMenuItems().GetFirst();
716 wxMenuItem
* item
= node
->GetData();
717 if ( !item
->IsSeparator() )
719 wxWindowID id
= item
->GetId();
720 wxUpdateUIEvent
event(id
);
721 event
.SetEventObject( source
);
723 if ( source
->ProcessEvent(event
) )
725 // if anything changed, update the changed attribute
726 if (event
.GetSetText())
727 SetLabel(id
, event
.GetText());
728 if (event
.GetSetChecked())
729 Check(id
, event
.GetChecked());
730 if (event
.GetSetEnabled())
731 Enable(id
, event
.GetEnabled());
734 // recurse to the submenus
735 if ( item
->GetSubMenu() )
736 item
->GetSubMenu()->UpdateUI(source
);
738 //else: item is a separator (which doesn't process update UI events)
740 node
= node
->GetNext();
744 bool wxMenuBase::SendEvent(int id
, int checked
)
746 wxCommandEvent
event(wxEVT_COMMAND_MENU_SELECTED
, id
);
747 event
.SetEventObject(this);
748 event
.SetInt(checked
);
750 bool processed
= false;
752 // Try the menu's event handler
755 wxEvtHandler
*handler
= GetEventHandler();
757 processed
= handler
->ProcessEvent(event
);
760 // Try the window the menu was popped up from (and up through the
764 const wxMenuBase
*menu
= this;
767 wxWindow
*win
= menu
->GetInvokingWindow();
770 processed
= win
->GetEventHandler()->ProcessEvent(event
);
774 menu
= menu
->GetParent();
781 // ----------------------------------------------------------------------------
782 // wxMenu attaching/detaching to/from menu bar
783 // ----------------------------------------------------------------------------
785 wxMenuBar
* wxMenuBase::GetMenuBar() const
788 return GetParent()->GetMenuBar();
792 void wxMenuBase::Attach(wxMenuBarBase
*menubar
)
794 // use Detach() instead!
795 wxASSERT_MSG( menubar
, _T("menu can't be attached to NULL menubar") );
797 // use IsAttached() to prevent this from happening
798 wxASSERT_MSG( !m_menuBar
, _T("attaching menu twice?") );
800 m_menuBar
= (wxMenuBar
*)menubar
;
803 void wxMenuBase::Detach()
805 // use IsAttached() to prevent this from happening
806 wxASSERT_MSG( m_menuBar
, _T("detaching unattached menu?") );
811 // ----------------------------------------------------------------------------
812 // wxMenu functions forwarded to wxMenuItem
813 // ----------------------------------------------------------------------------
815 void wxMenuBase::Enable( int id
, bool enable
)
817 wxMenuItem
*item
= FindItem(id
);
819 wxCHECK_RET( item
, wxT("wxMenu::Enable: no such item") );
821 item
->Enable(enable
);
824 bool wxMenuBase::IsEnabled( int id
) const
826 wxMenuItem
*item
= FindItem(id
);
828 wxCHECK_MSG( item
, false, wxT("wxMenu::IsEnabled: no such item") );
830 return item
->IsEnabled();
833 void wxMenuBase::Check( int id
, bool enable
)
835 wxMenuItem
*item
= FindItem(id
);
837 wxCHECK_RET( item
, wxT("wxMenu::Check: no such item") );
842 bool wxMenuBase::IsChecked( int id
) const
844 wxMenuItem
*item
= FindItem(id
);
846 wxCHECK_MSG( item
, false, wxT("wxMenu::IsChecked: no such item") );
848 return item
->IsChecked();
851 void wxMenuBase::SetLabel( int id
, const wxString
&label
)
853 wxMenuItem
*item
= FindItem(id
);
855 wxCHECK_RET( item
, wxT("wxMenu::SetLabel: no such item") );
857 item
->SetText(label
);
860 wxString
wxMenuBase::GetLabel( int id
) const
862 wxMenuItem
*item
= FindItem(id
);
864 wxCHECK_MSG( item
, wxEmptyString
, wxT("wxMenu::GetLabel: no such item") );
866 return item
->GetText();
869 void wxMenuBase::SetHelpString( int id
, const wxString
& helpString
)
871 wxMenuItem
*item
= FindItem(id
);
873 wxCHECK_RET( item
, wxT("wxMenu::SetHelpString: no such item") );
875 item
->SetHelp( helpString
);
878 wxString
wxMenuBase::GetHelpString( int id
) const
880 wxMenuItem
*item
= FindItem(id
);
882 wxCHECK_MSG( item
, wxEmptyString
, wxT("wxMenu::GetHelpString: no such item") );
884 return item
->GetHelp();
887 // ----------------------------------------------------------------------------
888 // wxMenuBarBase ctor and dtor
889 // ----------------------------------------------------------------------------
891 wxMenuBarBase::wxMenuBarBase()
894 m_menuBarFrame
= NULL
;
897 wxMenuBarBase::~wxMenuBarBase()
899 WX_CLEAR_LIST(wxMenuList
, m_menus
);
902 // ----------------------------------------------------------------------------
903 // wxMenuBar item access: the base class versions manage m_menus list, the
904 // derived class should reflect the changes in the real menubar
905 // ----------------------------------------------------------------------------
907 wxMenu
*wxMenuBarBase::GetMenu(size_t pos
) const
909 wxMenuList::compatibility_iterator node
= m_menus
.Item(pos
);
910 wxCHECK_MSG( node
, NULL
, wxT("bad index in wxMenuBar::GetMenu()") );
912 return node
->GetData();
915 bool wxMenuBarBase::Append(wxMenu
*menu
, const wxString
& WXUNUSED(title
))
917 wxCHECK_MSG( menu
, false, wxT("can't append NULL menu") );
919 m_menus
.Append(menu
);
925 bool wxMenuBarBase::Insert(size_t pos
, wxMenu
*menu
,
926 const wxString
& title
)
928 if ( pos
== m_menus
.GetCount() )
930 return wxMenuBarBase::Append(menu
, title
);
932 else // not at the end
934 wxCHECK_MSG( menu
, false, wxT("can't insert NULL menu") );
936 wxMenuList::compatibility_iterator node
= m_menus
.Item(pos
);
937 wxCHECK_MSG( node
, false, wxT("bad index in wxMenuBar::Insert()") );
939 m_menus
.Insert(node
, menu
);
946 wxMenu
*wxMenuBarBase::Replace(size_t pos
, wxMenu
*menu
,
947 const wxString
& WXUNUSED(title
))
949 wxCHECK_MSG( menu
, NULL
, wxT("can't insert NULL menu") );
951 wxMenuList::compatibility_iterator node
= m_menus
.Item(pos
);
952 wxCHECK_MSG( node
, NULL
, wxT("bad index in wxMenuBar::Replace()") );
954 wxMenu
*menuOld
= node
->GetData();
963 wxMenu
*wxMenuBarBase::Remove(size_t pos
)
965 wxMenuList::compatibility_iterator node
= m_menus
.Item(pos
);
966 wxCHECK_MSG( node
, NULL
, wxT("bad index in wxMenuBar::Remove()") );
968 wxMenu
*menu
= node
->GetData();
975 int wxMenuBarBase::FindMenu(const wxString
& title
) const
977 wxString label
= wxMenuItem::GetLabelFromText(title
);
979 size_t count
= GetMenuCount();
980 for ( size_t i
= 0; i
< count
; i
++ )
982 wxString title2
= GetLabelTop(i
);
983 if ( (title2
== title
) ||
984 (wxMenuItem::GetLabelFromText(title2
) == label
) )
995 // ----------------------------------------------------------------------------
996 // wxMenuBar attaching/detaching to/from the frame
997 // ----------------------------------------------------------------------------
999 void wxMenuBarBase::Attach(wxFrame
*frame
)
1001 wxASSERT_MSG( !IsAttached(), wxT("menubar already attached!") );
1003 m_menuBarFrame
= frame
;
1006 void wxMenuBarBase::Detach()
1008 wxASSERT_MSG( IsAttached(), wxT("detaching unattached menubar") );
1010 m_menuBarFrame
= NULL
;
1013 // ----------------------------------------------------------------------------
1014 // wxMenuBar searching for items
1015 // ----------------------------------------------------------------------------
1017 wxMenuItem
*wxMenuBarBase::FindItem(int id
, wxMenu
**menu
) const
1022 wxMenuItem
*item
= NULL
;
1023 size_t count
= GetMenuCount(), i
;
1024 wxMenuList::const_iterator it
;
1025 for ( i
= 0, it
= m_menus
.begin(); !item
&& (i
< count
); i
++, it
++ )
1027 item
= (*it
)->FindItem(id
, menu
);
1033 int wxMenuBarBase::FindMenuItem(const wxString
& menu
, const wxString
& item
) const
1035 wxString label
= wxMenuItem::GetLabelFromText(menu
);
1038 wxMenuList::compatibility_iterator node
;
1039 for ( node
= m_menus
.GetFirst(); node
; node
= node
->GetNext(), i
++ )
1041 if ( label
== wxMenuItem::GetLabelFromText(GetLabelTop(i
)) )
1042 return node
->GetData()->FindItem(item
);
1048 // ---------------------------------------------------------------------------
1049 // wxMenuBar functions forwarded to wxMenuItem
1050 // ---------------------------------------------------------------------------
1052 void wxMenuBarBase::Enable(int id
, bool enable
)
1054 wxMenuItem
*item
= FindItem(id
);
1056 wxCHECK_RET( item
, wxT("attempt to enable an item which doesn't exist") );
1058 item
->Enable(enable
);
1061 void wxMenuBarBase::Check(int id
, bool check
)
1063 wxMenuItem
*item
= FindItem(id
);
1065 wxCHECK_RET( item
, wxT("attempt to check an item which doesn't exist") );
1066 wxCHECK_RET( item
->IsCheckable(), wxT("attempt to check an uncheckable item") );
1071 bool wxMenuBarBase::IsChecked(int id
) const
1073 wxMenuItem
*item
= FindItem(id
);
1075 wxCHECK_MSG( item
, false, wxT("wxMenuBar::IsChecked(): no such item") );
1077 return item
->IsChecked();
1080 bool wxMenuBarBase::IsEnabled(int id
) const
1082 wxMenuItem
*item
= FindItem(id
);
1084 wxCHECK_MSG( item
, false, wxT("wxMenuBar::IsEnabled(): no such item") );
1086 return item
->IsEnabled();
1089 void wxMenuBarBase::SetLabel(int id
, const wxString
& label
)
1091 wxMenuItem
*item
= FindItem(id
);
1093 wxCHECK_RET( item
, wxT("wxMenuBar::SetLabel(): no such item") );
1095 item
->SetText(label
);
1098 wxString
wxMenuBarBase::GetLabel(int id
) const
1100 wxMenuItem
*item
= FindItem(id
);
1102 wxCHECK_MSG( item
, wxEmptyString
,
1103 wxT("wxMenuBar::GetLabel(): no such item") );
1105 return item
->GetText();
1108 void wxMenuBarBase::SetHelpString(int id
, const wxString
& helpString
)
1110 wxMenuItem
*item
= FindItem(id
);
1112 wxCHECK_RET( item
, wxT("wxMenuBar::SetHelpString(): no such item") );
1114 item
->SetHelp(helpString
);
1117 wxString
wxMenuBarBase::GetHelpString(int id
) const
1119 wxMenuItem
*item
= FindItem(id
);
1121 wxCHECK_MSG( item
, wxEmptyString
,
1122 wxT("wxMenuBar::GetHelpString(): no such item") );
1124 return item
->GetHelp();
1127 void wxMenuBarBase::UpdateMenus( void )
1129 wxEvtHandler
* source
;
1131 int nCount
= GetMenuCount();
1132 for (int n
= 0; n
< nCount
; n
++)
1134 menu
= GetMenu( n
);
1137 source
= menu
->GetEventHandler();
1139 menu
->UpdateUI( source
);
1144 #endif // wxUSE_MENUS