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 wxIMPLEMENT_ABSTRACT_CLASS(wxMenuItemImpl, wxObject);
26
~wxMenuItemImpl()27 wxMenuItemImpl::~wxMenuItemImpl()
28 {
29 }
30
wxMenuItem(wxMenu * pParentMenu,int id,const wxString & t,const wxString & strHelp,wxItemKind kind,wxMenu * pSubMenu)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, wxStrip_Menu).Upper() == wxT("EXIT") )
45 m_text = wxT("Quit\tCtrl+Q") ;
46
47 wxString text = wxStripMenuCodes(m_text, (pParentMenu != NULL && pParentMenu->GetNoEventsMode()) ? wxStrip_Accel : wxStrip_Menu);
48 if (text.IsEmpty() && !IsSeparator())
49 {
50 wxASSERT_MSG(wxIsStockID(GetId()), wxT("A non-stock menu item with an empty label?"));
51 text = wxGetStockLabel(GetId(), wxSTOCK_WITH_ACCELERATOR|wxSTOCK_WITH_MNEMONIC);
52 }
53
54 // use accessors for ID and Kind because they might have been changed in the base constructor
55 #if wxUSE_ACCEL
56 wxAcceleratorEntry *entry = wxAcceleratorEntry::Create( m_text ) ;
57 m_peer = wxMenuItemImpl::Create( this, pParentMenu, GetId(), text, entry, strHelp, GetKind(), pSubMenu );
58 delete entry;
59 #else
60 m_peer = wxMenuItemImpl::Create( this, pParentMenu, GetId(), text, NULL, strHelp, GetKind(), pSubMenu );
61 #endif // wxUSE_ACCEL/!wxUSE_ACCEL
62 }
63
~wxMenuItem()64 wxMenuItem::~wxMenuItem()
65 {
66 delete m_peer;
67 }
68
69 // change item state
70 // -----------------
71
SetBitmap(const wxBitmap & bitmap)72 void wxMenuItem::SetBitmap(const wxBitmap& bitmap)
73 {
74 m_bitmap = bitmap;
75 UpdateItemBitmap();
76 }
77
Enable(bool bDoEnable)78 void wxMenuItem::Enable(bool bDoEnable)
79 {
80 if (( m_isEnabled != bDoEnable
81 // avoid changing menuitem state when menu is disabled
82 // eg. BeginAppModalStateForWindow() will disable menus and ignore this change
83 // which in turn causes m_isEnabled to become out of sync with real menuitem state
84 )
85 // always update builtin menuitems
86 || ( GetId() == wxApp::s_macPreferencesMenuItemId
87 || GetId() == wxApp::s_macExitMenuItemId
88 || GetId() == wxApp::s_macAboutMenuItemId
89 ))
90 {
91 wxMenuItemBase::Enable( bDoEnable ) ;
92 UpdateItemStatus() ;
93 }
94 }
95
UncheckRadio()96 void wxMenuItem::UncheckRadio()
97 {
98 if ( m_isChecked )
99 {
100 wxMenuItemBase::Check( false ) ;
101 UpdateItemStatus() ;
102 }
103 }
104
Check(bool bDoCheck)105 void wxMenuItem::Check(bool bDoCheck)
106 {
107 wxCHECK_RET( IsCheckable() && !IsSeparator(), wxT("only checkable items may be checked") );
108
109 if ( m_isChecked != bDoCheck )
110 {
111 if ( GetKind() == wxITEM_RADIO )
112 {
113 if ( bDoCheck )
114 {
115 wxMenuItemBase::Check( bDoCheck ) ;
116 UpdateItemStatus() ;
117
118 // get the index of this item in the menu
119 const wxMenuItemList& items = m_parentMenu->GetMenuItems();
120 int pos = items.IndexOf(this);
121 wxCHECK_RET( pos != wxNOT_FOUND,
122 wxT("menuitem not found in the menu items list?") );
123
124 // get the radio group range
125 int start, end;
126 if ( !m_parentMenu->OSXGetRadioGroupRange(pos, &start, &end) )
127 {
128 wxFAIL_MSG( wxS("Menu radio item not part of radio group?") );
129 }
130
131 // also uncheck all the other items in this radio group
132 wxMenuItemList::compatibility_iterator node = items.Item(start);
133 for ( int n = start; n <= end && node; n++ )
134 {
135 if ( n != pos )
136 ((wxMenuItem*)node->GetData())->UncheckRadio();
137
138 node = node->GetNext();
139 }
140 }
141 }
142 else
143 {
144 wxMenuItemBase::Check( bDoCheck ) ;
145 UpdateItemStatus() ;
146 }
147 }
148 }
149
SetItemLabel(const wxString & text)150 void wxMenuItem::SetItemLabel(const wxString& text)
151 {
152 // don't do anything if label didn't change
153 if ( m_text == text )
154 return;
155
156 wxMenuItemBase::SetItemLabel(text);
157
158 UpdateItemText() ;
159 }
160
161
UpdateItemBitmap()162 void wxMenuItem::UpdateItemBitmap()
163 {
164 if ( !m_parentMenu )
165 return;
166
167 if ( m_bitmap.IsOk() )
168 {
169 GetPeer()->SetBitmap( m_bitmap );
170 }
171 }
172
UpdateItemStatus()173 void wxMenuItem::UpdateItemStatus()
174 {
175 if ( !m_parentMenu )
176 return ;
177
178 if ( IsSeparator() )
179 return ;
180
181 if ( IsCheckable() && IsChecked() )
182 GetPeer()->Check( true );
183 else
184 GetPeer()->Check( false );
185
186 GetPeer()->Enable( IsEnabled() );
187 }
188
UpdateItemText()189 void wxMenuItem::UpdateItemText()
190 {
191 if ( !m_parentMenu )
192 return ;
193
194 wxString text = wxStripMenuCodes(m_text, m_parentMenu != NULL && m_parentMenu->GetNoEventsMode() ? wxStrip_Accel : wxStrip_Menu);
195 if (text.IsEmpty() && !IsSeparator())
196 {
197 wxASSERT_MSG(wxIsStockID(GetId()), wxT("A non-stock menu item with an empty label?"));
198 text = wxGetStockLabel(GetId(), wxSTOCK_WITH_ACCELERATOR|wxSTOCK_WITH_MNEMONIC);
199 }
200
201 #if wxUSE_ACCEL
202 wxAcceleratorEntry *entry = wxAcceleratorEntry::Create( m_text ) ;
203 GetPeer()->SetLabel( text, entry );
204 delete entry ;
205 #else
206 GetPeer()->SetLabel( text, NULL );
207 #endif // wxUSE_ACCEL/!wxUSE_ACCEL
208 }
209
210 // ----------------------------------------------------------------------------
211 // wxMenuItemBase
212 // ----------------------------------------------------------------------------
213
New(wxMenu * parentMenu,int id,const wxString & name,const wxString & help,wxItemKind kind,wxMenu * subMenu)214 wxMenuItem *wxMenuItemBase::New(wxMenu *parentMenu,
215 int id,
216 const wxString& name,
217 const wxString& help,
218 wxItemKind kind,
219 wxMenu *subMenu)
220 {
221 return new wxMenuItem(parentMenu, id, name, help, kind, subMenu);
222 }
223
224 #endif
225