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