int wxMenuItem::MSGetMenuItemPos() const { if ( !m_parentMenu ) return -1; const HMENU hMenu = GetHMenuOf(m_parentMenu); if ( !hMenu ) return -1; const UINT id = GetMSWId(); const int menuItems = ::GetMenuItemCount(hMenu); for ( int i = 0; i < menuItems; i++ ) { const UINT state = ::GetMenuState(hMenu, i, MF_BYPOSITION); if ( state == (UINT)-1 ) { // This indicates that the item at this position and is not // supposed to happen here, but test for it just in case. continue; } if ( state & MF_POPUP ) { if ( ::GetSubMenu(hMenu, i) == (HMENU)wxUIntToPtr(id) ) return i; } else if ( !(state & MF_SEPARATOR) ) { if ( ::GetMenuItemID(hMenu, i) == id ) return i; } } return -1; }
bool wxMenuItem::IsChecked() const { // fix that RTTI is always getting the correct state (separators cannot be // checked, but the Windows call below returns true if ( IsSeparator() ) return false; // the item might not be attached to a menu yet // // TODO: shouldn't we just always call the base class version? It seems // like it ought to always be in sync if ( !m_parentMenu ) return wxMenuItemBase::IsChecked(); HMENU hmenu = GetHMenuOf(m_parentMenu); int flag = ::GetMenuState(hmenu, GetMSWId(), MF_BYCOMMAND); return (flag & MF_CHECKED) != 0; }
void wxMenuItem::Enable(bool enable) { if ( m_isEnabled == enable ) return; if ( m_parentMenu ) { long rc = EnableMenuItem(GetHMenuOf(m_parentMenu), GetMSWId(), MF_BYCOMMAND | (enable ? MF_ENABLED : MF_GRAYED)); if ( rc == -1 ) { wxLogLastError(wxT("EnableMenuItem")); } } wxMenuItemBase::Enable(enable); }
void wxMenuItem::Check(bool check) { wxCHECK_RET( IsCheckable(), wxT("only checkable items may be checked") ); if ( m_isChecked == check ) return; if ( m_parentMenu ) { int flags = check ? MF_CHECKED : MF_UNCHECKED; HMENU hmenu = GetHMenuOf(m_parentMenu); if ( GetKind() == wxITEM_RADIO ) { // it doesn't make sense to uncheck a radio item -- what would this // do? if ( !check ) return; // get the index of this item in the menu const wxMenuItemList& items = m_parentMenu->GetMenuItems(); int pos = items.IndexOf(this); wxCHECK_RET( pos != wxNOT_FOUND, wxT("menuitem not found in the menu items list?") ); // get the radio group range int start, end; if ( !m_parentMenu->MSWGetRadioGroupRange(pos, &start, &end) ) { wxFAIL_MSG( wxT("Menu radio item not part of radio group?") ); return; } #ifdef __WIN32__ // calling CheckMenuRadioItem() with such parameters hangs my system // (NT4 SP6) and I suspect this could happen to the others as well, // so don't do it! wxCHECK_RET( start != -1 && end != -1, wxT("invalid ::CheckMenuRadioItem() parameter(s)") ); if ( !::CheckMenuRadioItem(hmenu, start, // the first radio group item end, // the last one pos, // the one to check MF_BYPOSITION) ) { wxLogLastError(wxT("CheckMenuRadioItem")); } #endif // __WIN32__ // also uncheck all the other items in this radio group wxMenuItemList::compatibility_iterator node = items.Item(start); for ( int n = start; n <= end && node; n++ ) { if ( n != pos ) { node->GetData()->m_isChecked = false; } node = node->GetNext(); } } else // check item { if ( ::CheckMenuItem(hmenu, GetMSWId(), MF_BYCOMMAND | flags) == (DWORD)-1 ) { wxFAIL_MSG(wxT("CheckMenuItem() failed, item not in the menu?")); } } } wxMenuItemBase::Check(check); }
void wxMenuItem::DoSetBitmap(const wxBitmap& bmp, bool bChecked) { if ( bChecked ) { if ( m_bmpChecked.IsSameAs(bmp) ) return; m_bmpChecked = bmp; } else { if ( m_bmpUnchecked.IsSameAs(bmp) ) return; m_bmpUnchecked = bmp; } #if wxUSE_OWNER_DRAWN // already marked as owner-drawn, cannot be reverted if ( IsOwnerDrawn() ) return; if ( MSWMustUseOwnerDrawn() ) { SetOwnerDrawn(true); // Parent menu has to be rearranged/recalculated in this case // (all other menu items have to be also set to owner-drawn mode). if ( m_parentMenu ) { size_t pos; wxMenuItem *item = m_parentMenu->FindChildItem(GetMSWId(), &pos); if ( item ) { wxCHECK_RET( item == this, wxS("Non unique menu item ID?") ); m_parentMenu->Remove(this); m_parentMenu->Insert(pos, this); } //else: the item hasn't been inserted into the parent menu yet } return; } #endif // wxUSE_OWNER_DRAWN // the item can be not attached to any menu yet and SetBitmap() is still // valid to call in this case and should do nothing else if ( !m_parentMenu ) return; HMENU hMenu = GetHMenuOf(m_parentMenu); if ( !hMenu ) return; const UINT id = GetMSWId(); const UINT state = ::GetMenuState(hMenu, id, MF_BYCOMMAND); if ( state == (UINT)-1 ) return; // update the bitmap of the native menu item // don't set hbmpItem for the checkable items as it would // be used for both checked and unchecked state WinStruct<MENUITEMINFO> mii; if ( IsCheckable() ) { mii.fMask = MIIM_CHECKMARKS; mii.hbmpChecked = GetHBitmapForMenu(true); mii.hbmpUnchecked = GetHBitmapForMenu(false); } else { mii.fMask = MIIM_BITMAP; mii.hbmpItem = GetHBitmapForMenu(); } if ( !::SetMenuItemInfo(hMenu, id, FALSE, &mii) ) { wxLogLastError(wxT("SetMenuItemInfo")); } }
void wxMenuItem::SetItemLabel(const wxString& txt) { wxString text = txt; // don't do anything if label didn't change if ( m_text == txt ) return; // wxMenuItemBase will do stock ID checks wxMenuItemBase::SetItemLabel(text); // the item can be not attached to any menu yet and SetItemLabel() is still // valid to call in this case and should do nothing else if ( !m_parentMenu ) return; #if wxUSE_ACCEL m_parentMenu->UpdateAccel(this); #endif // wxUSE_ACCEL const UINT id = GetMSWId(); HMENU hMenu = GetHMenuOf(m_parentMenu); if ( !hMenu ) return; const UINT state = ::GetMenuState(hMenu, id, MF_BYCOMMAND); if ( state == (UINT)-1 ) return; // update the text of the native menu item WinStruct<MENUITEMINFO> info; // surprisingly, calling SetMenuItemInfo() with just MIIM_STRING doesn't // work as it resets the menu bitmap, so we need to first get the old item // state and then modify it const bool isLaterThanWin95 = wxGetWinVersion() > wxWinVersion_95; info.fMask = MIIM_STATE | MIIM_ID | MIIM_SUBMENU | MIIM_CHECKMARKS | MIIM_DATA; if ( isLaterThanWin95 ) info.fMask |= MIIM_BITMAP | MIIM_FTYPE; else info.fMask |= MIIM_TYPE; if ( !::GetMenuItemInfo(hMenu, id, FALSE, &info) ) { wxLogLastError(wxT("GetMenuItemInfo")); return; } #if wxUSE_OWNER_DRAWN // Don't set the text for the owner drawn items, they don't use it and even // though setting it doesn't seem to actually do any harm under Windows 7, // avoid doing this relatively nonsensical operation just in case it does // break something on other, past or future, Windows versions. // // Notice that we do need to call SetMenuItemInfo() even for the ownerdrawn // items however as otherwise their size wouldn't be recalculated as // WM_MEASUREITEM wouldn't be sent and this could result in display // problems if the length of the menu item changed significantly. // // Also notice that we shouldn't use our IsOwnerDrawn() because it can be // true because it was set by e.g. SetBitmap(), even if the item wasn't // made owner drawn at Windows level. if ( !(state & MF_OWNERDRAW) ) #endif // wxUSE_OWNER_DRAWN { if ( isLaterThanWin95 ) info.fMask |= MIIM_STRING; //else: MIIM_TYPE already specified info.dwTypeData = wxMSW_CONV_LPTSTR(m_text); info.cch = m_text.length(); } if ( !::SetMenuItemInfo(hMenu, id, FALSE, &info) ) { wxLogLastError(wxT("SetMenuItemInfo")); } }
void wxMenuItem::SetItemLabel(const wxString& txt) { wxString text = txt; // don't do anything if label didn't change if ( m_text == txt ) return; // wxMenuItemBase will do stock ID checks wxMenuItemBase::SetItemLabel(text); // the item can be not attached to any menu yet and SetItemLabel() is still // valid to call in this case and should do nothing else if ( !m_parentMenu ) return; #if wxUSE_ACCEL m_parentMenu->UpdateAccel(this); #endif // wxUSE_ACCEL const UINT id = GetMSWId(); HMENU hMenu = GetHMenuOf(m_parentMenu); if ( !hMenu || ::GetMenuState(hMenu, id, MF_BYCOMMAND) == (UINT)-1 ) return; #if wxUSE_OWNER_DRAWN if ( IsOwnerDrawn() ) { // we don't need to do anything for owner drawn items, they will redraw // themselves using the new text the next time they're displayed return; } #endif // owner drawn // update the text of the native menu item WinStruct<MENUITEMINFO> info; // surprisingly, calling SetMenuItemInfo() with just MIIM_STRING doesn't // work as it resets the menu bitmap, so we need to first get the old item // state and then modify it const bool isLaterThanWin95 = wxGetWinVersion() > wxWinVersion_95; info.fMask = MIIM_STATE | MIIM_ID | MIIM_SUBMENU | MIIM_CHECKMARKS | MIIM_DATA; if ( isLaterThanWin95 ) info.fMask |= MIIM_BITMAP | MIIM_FTYPE; else info.fMask |= MIIM_TYPE; if ( !::GetMenuItemInfo(hMenu, id, FALSE, &info) ) { wxLogLastError(wxT("GetMenuItemInfo")); return; } if ( isLaterThanWin95 ) info.fMask |= MIIM_STRING; //else: MIIM_TYPE already specified info.dwTypeData = (LPTSTR)m_text.wx_str(); info.cch = m_text.length(); if ( !::SetMenuItemInfo(hMenu, id, FALSE, &info) ) { wxLogLastError(wxT("SetMenuItemInfo")); } }