Remove all lines containing cvs/svn "$Id$" keyword.
[wxWidgets.git] / src / osx / menuitem_osx.cpp
1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: src/osx/menuitem_osx.cpp
3 // Purpose: wxMenuItem implementation
4 // Author: Stefan Csomor
5 // Modified by:
6 // Created: 1998-01-01
7 // Copyright: (c) Stefan Csomor
8 // Licence: wxWindows licence
9 ///////////////////////////////////////////////////////////////////////////////
10
11 #include "wx/wxprec.h"
12
13 #if wxUSE_MENUS
14
15 #include "wx/menuitem.h"
16 #include "wx/stockitem.h"
17
18 #ifndef WX_PRECOMP
19 #include "wx/app.h"
20 #include "wx/menu.h"
21 #endif // WX_PRECOMP
22
23 #include "wx/osx/private.h"
24
25 IMPLEMENT_ABSTRACT_CLASS( wxMenuItemImpl , wxObject )
26
27 wxMenuItemImpl::~wxMenuItemImpl()
28 {
29 }
30
31 wxMenuItem::wxMenuItem(wxMenu *pParentMenu,
32 int id,
33 const wxString& t,
34 const wxString& strHelp,
35 wxItemKind kind,
36 wxMenu *pSubMenu)
37 :wxMenuItemBase(pParentMenu, id, t, strHelp, kind, pSubMenu)
38 {
39 wxASSERT_MSG( id != 0 || pSubMenu != NULL , wxT("A MenuItem ID of Zero does not work under Mac") ) ;
40
41 // In other languages there is no difference in naming the Exit/Quit menu item between MacOS and Windows guidelines
42 // therefore these item must not be translated
43 if (pParentMenu != NULL && !pParentMenu->GetNoEventsMode())
44 if ( wxStripMenuCodes(m_text).Upper() == wxT("EXIT") )
45 m_text = wxT("Quit\tCtrl+Q") ;
46
47 m_radioGroup.start = -1;
48 m_isRadioGroupStart = false;
49
50 wxString text = wxStripMenuCodes(m_text, (pParentMenu != NULL && pParentMenu->GetNoEventsMode()) ? wxStrip_Accel : wxStrip_All);
51 if (text.IsEmpty() && !IsSeparator())
52 {
53 wxASSERT_MSG(wxIsStockID(GetId()), wxT("A non-stock menu item with an empty label?"));
54 text = wxGetStockLabel(GetId(), wxSTOCK_WITH_ACCELERATOR|wxSTOCK_WITH_MNEMONIC);
55 }
56
57 wxAcceleratorEntry *entry = wxAcceleratorEntry::Create( m_text ) ;
58 // use accessors for ID and Kind because they might have been changed in the base constructor
59 m_peer = wxMenuItemImpl::Create( this, pParentMenu, GetId(), text, entry, strHelp, GetKind(), pSubMenu );
60 delete entry;
61 }
62
63 wxMenuItem::~wxMenuItem()
64 {
65 delete m_peer;
66 }
67
68 // change item state
69 // -----------------
70
71 void wxMenuItem::SetBitmap(const wxBitmap& bitmap)
72 {
73 m_bitmap = bitmap;
74 UpdateItemBitmap();
75 }
76
77 void wxMenuItem::Enable(bool bDoEnable)
78 {
79 if (( m_isEnabled != bDoEnable
80 // avoid changing menuitem state when menu is disabled
81 // eg. BeginAppModalStateForWindow() will disable menus and ignore this change
82 // which in turn causes m_isEnabled to become out of sync with real menuitem state
83 #if wxOSX_USE_CARBON
84 && !(m_parentMenu && !IsMenuItemEnabled(MAC_WXHMENU(m_parentMenu->GetHMenu()), 0))
85 #endif
86 )
87 // always update builtin menuitems
88 || ( GetId() == wxApp::s_macPreferencesMenuItemId
89 || GetId() == wxApp::s_macExitMenuItemId
90 || GetId() == wxApp::s_macAboutMenuItemId
91 ))
92 {
93 wxMenuItemBase::Enable( bDoEnable ) ;
94 UpdateItemStatus() ;
95 }
96 }
97
98 void wxMenuItem::UncheckRadio()
99 {
100 if ( m_isChecked )
101 {
102 wxMenuItemBase::Check( false ) ;
103 UpdateItemStatus() ;
104 }
105 }
106
107 void wxMenuItem::Check(bool bDoCheck)
108 {
109 wxCHECK_RET( IsCheckable() && !IsSeparator(), wxT("only checkable items may be checked") );
110
111 if ( m_isChecked != bDoCheck )
112 {
113 if ( GetKind() == wxITEM_RADIO )
114 {
115 if ( bDoCheck )
116 {
117 wxMenuItemBase::Check( bDoCheck ) ;
118 UpdateItemStatus() ;
119
120 // get the index of this item in the menu
121 const wxMenuItemList& items = m_parentMenu->GetMenuItems();
122 int pos = items.IndexOf(this);
123 wxCHECK_RET( pos != wxNOT_FOUND,
124 wxT("menuitem not found in the menu items list?") );
125
126 // get the radio group range
127 int start, end;
128
129 if ( m_isRadioGroupStart )
130 {
131 // we already have all information we need
132 start = pos;
133 end = m_radioGroup.end;
134 }
135 else // next radio group item
136 {
137 // get the radio group end from the start item
138 start = m_radioGroup.start;
139 end = items.Item(start)->GetData()->m_radioGroup.end;
140 }
141
142 // also uncheck all the other items in this radio group
143 wxMenuItemList::compatibility_iterator node = items.Item(start);
144 for ( int n = start; n <= end && node; n++ )
145 {
146 if ( n != pos )
147 ((wxMenuItem*)node->GetData())->UncheckRadio();
148
149 node = node->GetNext();
150 }
151 }
152 }
153 else
154 {
155 wxMenuItemBase::Check( bDoCheck ) ;
156 UpdateItemStatus() ;
157 }
158 }
159 }
160
161 void wxMenuItem::SetItemLabel(const wxString& text)
162 {
163 // don't do anything if label didn't change
164 if ( m_text == text )
165 return;
166
167 wxMenuItemBase::SetItemLabel(text);
168
169 UpdateItemText() ;
170 }
171
172
173 void wxMenuItem::UpdateItemBitmap()
174 {
175 if ( !m_parentMenu )
176 return;
177
178 if ( m_bitmap.IsOk() )
179 {
180 GetPeer()->SetBitmap( m_bitmap );
181 }
182 }
183
184 void wxMenuItem::UpdateItemStatus()
185 {
186 if ( !m_parentMenu )
187 return ;
188
189 if ( IsSeparator() )
190 return ;
191
192 if ( IsCheckable() && IsChecked() )
193 GetPeer()->Check( true );
194 else
195 GetPeer()->Check( false );
196
197 GetPeer()->Enable( IsEnabled() );
198 }
199
200 void wxMenuItem::UpdateItemText()
201 {
202 if ( !m_parentMenu )
203 return ;
204
205 wxString text = wxStripMenuCodes(m_text, m_parentMenu != NULL && m_parentMenu->GetNoEventsMode() ? wxStrip_Accel : wxStrip_All);
206 if (text.IsEmpty() && !IsSeparator())
207 {
208 wxASSERT_MSG(wxIsStockID(GetId()), wxT("A non-stock menu item with an empty label?"));
209 text = wxGetStockLabel(GetId(), wxSTOCK_WITH_ACCELERATOR|wxSTOCK_WITH_MNEMONIC);
210 }
211
212 wxAcceleratorEntry *entry = wxAcceleratorEntry::Create( m_text ) ;
213 GetPeer()->SetLabel( text, entry );
214 delete entry ;
215 }
216
217 // radio group stuff
218 // -----------------
219
220 void wxMenuItem::SetAsRadioGroupStart(bool start)
221 {
222 m_isRadioGroupStart = start;
223 }
224
225 void wxMenuItem::SetRadioGroupStart(int start)
226 {
227 wxASSERT_MSG( !m_isRadioGroupStart,
228 wxT("should only be called for the next radio items") );
229
230 m_radioGroup.start = start;
231 }
232
233 void wxMenuItem::SetRadioGroupEnd(int end)
234 {
235 wxASSERT_MSG( m_isRadioGroupStart,
236 wxT("should only be called for the first radio item") );
237
238 m_radioGroup.end = end;
239 }
240
241 bool wxMenuItem::IsRadioGroupStart() const
242 {
243 return m_isRadioGroupStart;
244 }
245
246 int wxMenuItem::GetRadioGroupStart() const
247 {
248 wxASSERT_MSG( !m_isRadioGroupStart,
249 wxS("shouldn't be called for the first radio item") );
250
251 return m_radioGroup.start;
252 }
253
254 int wxMenuItem::GetRadioGroupEnd() const
255 {
256 wxASSERT_MSG( m_isRadioGroupStart,
257 wxS("shouldn't be called for the first radio item") );
258
259 return m_radioGroup.end;
260 }
261
262 // ----------------------------------------------------------------------------
263 // wxMenuItemBase
264 // ----------------------------------------------------------------------------
265
266 wxMenuItem *wxMenuItemBase::New(wxMenu *parentMenu,
267 int id,
268 const wxString& name,
269 const wxString& help,
270 wxItemKind kind,
271 wxMenu *subMenu)
272 {
273 return new wxMenuItem(parentMenu, id, name, help, kind, subMenu);
274 }
275
276 #endif