1/////////////////////////////////////////////////////////////////////////////// 2// Name: src/mac/carbon/menuitem.cpp 3// Purpose: wxMenuItem implementation 4// Author: Stefan Csomor 5// Modified by: 6// Created: 1998-01-01 7// RCS-ID: $Id: menuitem.cpp 48053 2007-08-13 17:07:01Z JS $ 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/mac/uma.h" 23 24IMPLEMENT_DYNAMIC_CLASS(wxMenuItem, wxObject) 25 26 27wxMenuItem::wxMenuItem(wxMenu *pParentMenu, 28 int id, 29 const wxString& text, 30 const wxString& strHelp, 31 wxItemKind kind, 32 wxMenu *pSubMenu) 33 :wxMenuItemBase(pParentMenu, id, text, strHelp, kind, pSubMenu) 34{ 35 wxASSERT_MSG( id != 0 || pSubMenu != NULL , wxT("A MenuItem ID of Zero does not work under Mac") ) ; 36 37 // In other languages there is no difference in naming the Exit/Quit menu item between MacOS and Windows guidelines 38 // therefore these item must not be translated 39 if ( wxStripMenuCodes(m_text).Upper() == wxT("EXIT") ) 40 m_text = wxT("Quit\tCtrl+Q") ; 41 42 m_radioGroup.start = -1; 43 m_isRadioGroupStart = false; 44} 45 46wxMenuItem::~wxMenuItem() 47{ 48} 49 50// change item state 51// ----------------- 52 53void wxMenuItem::SetBitmap(const wxBitmap& bitmap) 54{ 55 m_bitmap = bitmap; 56 UpdateItemBitmap(); 57} 58 59void wxMenuItem::UpdateItemBitmap() 60{ 61 if ( !m_parentMenu ) 62 return ; 63 64 MenuHandle mhandle = MAC_WXHMENU(m_parentMenu->GetHMenu()) ; 65 MenuItemIndex index = m_parentMenu->MacGetIndexFromItem( this ) ; 66 DoUpdateItemBitmap( mhandle, index ); 67} 68 69void wxMenuItem::DoUpdateItemBitmap( WXHMENU menu, wxUint16 index) 70{ 71 MenuHandle mhandle = (MenuHandle) menu; 72 73 if ( mhandle == NULL || index == 0) 74 return ; 75 76 if ( m_bitmap.Ok() ) 77 { 78#if wxUSE_BMPBUTTON 79 ControlButtonContentInfo info ; 80 wxMacCreateBitmapButton( &info , m_bitmap ) ; 81 if ( info.contentType != kControlNoContent ) 82 { 83 if ( info.contentType == kControlContentIconRef ) 84 SetMenuItemIconHandle( mhandle , index , 85 kMenuIconRefType , (Handle) info.u.iconRef ) ; 86 else if ( info.contentType == kControlContentCGImageRef ) 87 SetMenuItemIconHandle( mhandle , index , 88 kMenuCGImageRefType , (Handle) info.u.imageRef ) ; 89 } 90 wxMacReleaseBitmapButton( &info ) ; 91#endif 92 } 93} 94 95void wxMenuItem::UpdateItemStatus() 96{ 97 if ( !m_parentMenu ) 98 return ; 99 100 if ( IsSeparator() ) 101 return ; 102 103#if TARGET_CARBON 104 if ( UMAGetSystemVersion() >= 0x1000 && GetId() == wxApp::s_macPreferencesMenuItemId) 105 { 106 if ( !IsEnabled() ) 107 DisableMenuCommand( NULL , kHICommandPreferences ) ; 108 else 109 EnableMenuCommand( NULL , kHICommandPreferences ) ; 110 } 111 112 if ( UMAGetSystemVersion() >= 0x1000 && GetId() == wxApp::s_macExitMenuItemId) 113 { 114 if ( !IsEnabled() ) 115 DisableMenuCommand( NULL , kHICommandQuit ) ; 116 else 117 EnableMenuCommand( NULL , kHICommandQuit ) ; 118 } 119#endif 120 121 { 122 MenuHandle mhandle = MAC_WXHMENU(m_parentMenu->GetHMenu()) ; 123 MenuItemIndex index = m_parentMenu->MacGetIndexFromItem( this ) ; 124 if ( mhandle == NULL || index == 0) 125 return ; 126 127 UMAEnableMenuItem( mhandle , index , m_isEnabled ) ; 128 if ( IsCheckable() && IsChecked() ) 129 ::SetItemMark( mhandle , index , 0x12 ) ; // checkmark 130 else 131 ::SetItemMark( mhandle , index , 0 ) ; // no mark 132 133 UMASetMenuItemText( mhandle , index , wxStripMenuCodes(m_text) , wxFont::GetDefaultEncoding() ) ; 134 wxAcceleratorEntry *entry = wxAcceleratorEntry::Create( m_text ) ; 135 UMASetMenuItemShortcut( mhandle , index , entry ) ; 136 delete entry ; 137 } 138} 139 140void wxMenuItem::UpdateItemText() 141{ 142 if ( !m_parentMenu ) 143 return ; 144 145 MenuHandle mhandle = MAC_WXHMENU(m_parentMenu->GetHMenu()) ; 146 MenuItemIndex index = m_parentMenu->MacGetIndexFromItem( this ) ; 147 if (mhandle == NULL || index == 0) 148 return ; 149 150 wxString text = m_text; 151 if (text.IsEmpty() && !IsSeparator()) 152 { 153 wxASSERT_MSG(wxIsStockID(GetId()), wxT("A non-stock menu item with an empty label?")); 154 text = wxGetStockLabel(GetId(), wxSTOCK_WITH_ACCELERATOR|wxSTOCK_WITH_MNEMONIC); 155 } 156 157 UMASetMenuItemText( mhandle , index , wxStripMenuCodes(text) , wxFont::GetDefaultEncoding() ) ; 158 wxAcceleratorEntry *entry = wxAcceleratorEntry::Create( text ) ; 159 UMASetMenuItemShortcut( mhandle , index , entry ) ; 160 delete entry ; 161} 162 163void wxMenuItem::Enable(bool bDoEnable) 164{ 165 if (( m_isEnabled != bDoEnable 166#if TARGET_CARBON 167 // avoid changing menuitem state when menu is disabled 168 // eg. BeginAppModalStateForWindow() will disable menus and ignore this change 169 // which in turn causes m_isEnabled to become out of sync with real menuitem state 170 && !(m_parentMenu && !IsMenuItemEnabled(MAC_WXHMENU(m_parentMenu->GetHMenu()), 0)) ) 171 // always update builtin menuitems 172 || ( GetId() == wxApp::s_macPreferencesMenuItemId 173 || GetId() == wxApp::s_macExitMenuItemId 174 || GetId() == wxApp::s_macAboutMenuItemId 175#endif 176 )) 177 { 178 wxMenuItemBase::Enable( bDoEnable ) ; 179 UpdateItemStatus() ; 180 } 181} 182 183void wxMenuItem::UncheckRadio() 184{ 185 if ( m_isChecked ) 186 { 187 wxMenuItemBase::Check( false ) ; 188 UpdateItemStatus() ; 189 } 190} 191 192void wxMenuItem::Check(bool bDoCheck) 193{ 194 wxCHECK_RET( IsCheckable() && !IsSeparator(), wxT("only checkable items may be checked") ); 195 196 if ( m_isChecked != bDoCheck ) 197 { 198 if ( GetKind() == wxITEM_RADIO ) 199 { 200 if ( bDoCheck ) 201 { 202 wxMenuItemBase::Check( bDoCheck ) ; 203 UpdateItemStatus() ; 204 205 // get the index of this item in the menu 206 const wxMenuItemList& items = m_parentMenu->GetMenuItems(); 207 int pos = items.IndexOf(this); 208 wxCHECK_RET( pos != wxNOT_FOUND, 209 _T("menuitem not found in the menu items list?") ); 210 211 // get the radio group range 212 int start, end; 213 214 if ( m_isRadioGroupStart ) 215 { 216 // we already have all information we need 217 start = pos; 218 end = m_radioGroup.end; 219 } 220 else // next radio group item 221 { 222 // get the radio group end from the start item 223 start = m_radioGroup.start; 224 end = items.Item(start)->GetData()->m_radioGroup.end; 225 } 226 227 // also uncheck all the other items in this radio group 228 wxMenuItemList::compatibility_iterator node = items.Item(start); 229 for ( int n = start; n <= end && node; n++ ) 230 { 231 if ( n != pos ) 232 ((wxMenuItem*)node->GetData())->UncheckRadio(); 233 234 node = node->GetNext(); 235 } 236 } 237 } 238 else 239 { 240 wxMenuItemBase::Check( bDoCheck ) ; 241 UpdateItemStatus() ; 242 } 243 } 244} 245 246void wxMenuItem::SetText(const wxString& text) 247{ 248 // don't do anything if label didn't change 249 if ( m_text == text ) 250 return; 251 252 wxMenuItemBase::SetText(text); 253 254 UpdateItemText() ; 255} 256 257// radio group stuff 258// ----------------- 259 260void wxMenuItem::SetAsRadioGroupStart() 261{ 262 m_isRadioGroupStart = true; 263} 264 265void wxMenuItem::SetRadioGroupStart(int start) 266{ 267 wxASSERT_MSG( !m_isRadioGroupStart, 268 wxT("should only be called for the next radio items") ); 269 270 m_radioGroup.start = start; 271} 272 273void wxMenuItem::SetRadioGroupEnd(int end) 274{ 275 wxASSERT_MSG( m_isRadioGroupStart, 276 wxT("should only be called for the first radio item") ); 277 278 m_radioGroup.end = end; 279} 280 281// ---------------------------------------------------------------------------- 282// wxMenuItemBase 283// ---------------------------------------------------------------------------- 284 285/* static */ 286wxString wxMenuItemBase::GetLabelFromText(const wxString& text) 287{ 288 return wxStripMenuCodes(text); 289} 290 291wxMenuItem *wxMenuItemBase::New(wxMenu *parentMenu, 292 int id, 293 const wxString& name, 294 const wxString& help, 295 wxItemKind kind, 296 wxMenu *subMenu) 297{ 298 return new wxMenuItem(parentMenu, id, name, help, kind, subMenu); 299} 300