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