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