Fix failing Win32 calls with checkable menu item.
Since r76202 InsertMenuItem is used when adding checkable menu items even without a bitmap. The call fails because hbmpChecked and hbmpUnchecked are set to HBMMENU_CALLBACK on pre-Vista, making the menu owner drawn unnecessarily. Fix by adding GetHBitmapForMenuCheckable which is used when assigning values to hbmpChecked and hbmpUnchecked. GetHBitmapForMenu remains unchanged (for possible porting reasons) and is used for hBmpItem only. git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@76757 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
@@ -117,9 +117,12 @@ private:
|
||||
bool MSWMustUseOwnerDrawn();
|
||||
#endif // wxUSE_OWNER_DRAWN
|
||||
|
||||
// helper function to get a handle of bitmap associated with item
|
||||
// helper function to get a handle for normal bitmap associated with item
|
||||
WXHBITMAP GetHBitmapForMenu(bool checked = true);
|
||||
|
||||
// helper function to get a handle for checkable bitmap associated with item
|
||||
WXHBITMAP GetHBitmapForMenuCheckable(bool checked);
|
||||
|
||||
// helper function to set/change the bitmap
|
||||
void DoSetBitmap(const wxBitmap& bmp, bool bChecked);
|
||||
|
||||
|
@@ -25,7 +25,9 @@
|
||||
|
||||
#ifndef WX_PRECOMP
|
||||
#include "wx/app.h"
|
||||
#include "wx/bitmap.h"
|
||||
#include "wx/frame.h"
|
||||
#include "wx/image.h"
|
||||
#include "wx/menu.h"
|
||||
#include "wx/msgdlg.h"
|
||||
#include "wx/log.h"
|
||||
@@ -607,6 +609,33 @@ MyFrame::MyFrame()
|
||||
testMenu->Append(Menu_Test_Normal, wxT("&Normal item"));
|
||||
testMenu->AppendSeparator();
|
||||
testMenu->AppendCheckItem(Menu_Test_Check, wxT("&Check item"));
|
||||
|
||||
#ifdef __WXMSW__
|
||||
#if wxUSE_IMAGE
|
||||
wxBitmap bmpUnchecked(8, 8);
|
||||
|
||||
wxImage imageChecked(8, 8);
|
||||
imageChecked.Clear(0xff);
|
||||
wxBitmap bmpChecked(imageChecked);
|
||||
|
||||
wxMenuItem *checkedBitmapItem = new wxMenuItem(testMenu, wxID_ANY,
|
||||
"Check item with bitmaps", "", wxITEM_CHECK);
|
||||
checkedBitmapItem->SetBitmaps(bmpChecked, bmpUnchecked);
|
||||
testMenu->Append(checkedBitmapItem);
|
||||
|
||||
checkedBitmapItem = new wxMenuItem(testMenu, wxID_ANY,
|
||||
"Check item with bitmaps set afterwards", "", wxITEM_CHECK);
|
||||
testMenu->Append(checkedBitmapItem);
|
||||
checkedBitmapItem->SetBitmaps(bmpChecked, bmpUnchecked);
|
||||
|
||||
checkedBitmapItem = new wxMenuItem(testMenu, wxID_ANY,
|
||||
"Check item with bitmaps set afterwards (initially checked)", "", wxITEM_CHECK);
|
||||
testMenu->Append(checkedBitmapItem);
|
||||
checkedBitmapItem->Check();
|
||||
checkedBitmapItem->SetBitmaps(bmpChecked, bmpUnchecked);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
testMenu->AppendSeparator();
|
||||
testMenu->AppendRadioItem(Menu_Test_Radio1, wxT("Radio item &1"));
|
||||
testMenu->AppendRadioItem(Menu_Test_Radio2, wxT("Radio item &2"));
|
||||
|
@@ -573,8 +573,8 @@ bool wxMenu::DoInsertOrAppend(wxMenuItem *pItem, size_t pos)
|
||||
if ( pItem->IsCheckable() )
|
||||
{
|
||||
mii.fMask |= MIIM_CHECKMARKS;
|
||||
mii.hbmpChecked = pItem->GetHBitmapForMenu(true);
|
||||
mii.hbmpUnchecked = pItem->GetHBitmapForMenu(false);
|
||||
mii.hbmpChecked = pItem->GetHBitmapForMenuCheckable(true);
|
||||
mii.hbmpUnchecked = pItem->GetHBitmapForMenuCheckable(false);
|
||||
}
|
||||
else if ( pItem->GetBitmap().IsOk() )
|
||||
{
|
||||
|
@@ -807,8 +807,8 @@ void wxMenuItem::DoSetBitmap(const wxBitmap& bmp, bool bChecked)
|
||||
if ( IsCheckable() )
|
||||
{
|
||||
mii.fMask = MIIM_CHECKMARKS;
|
||||
mii.hbmpChecked = GetHBitmapForMenu(true);
|
||||
mii.hbmpUnchecked = GetHBitmapForMenu(false);
|
||||
mii.hbmpChecked = GetHBitmapForMenuCheckable(true);
|
||||
mii.hbmpUnchecked = GetHBitmapForMenuCheckable(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1184,6 +1184,52 @@ bool wxMenuItem::OnDrawItem(wxDC& dc, const wxRect& rc,
|
||||
namespace
|
||||
{
|
||||
|
||||
// Returns the HBITMAP to use in MENUITEMINFO, either for hBmpItem (then
|
||||
// forCheckableItem is false) or for hbmpChecked/hBmpUnchecked
|
||||
// usage (forCheckableItem is true). The difference is needed because
|
||||
// HBMMENU_CALLBACK can only be used for hBmpItem items.
|
||||
HBITMAP DoGetHBitmapForMenu(wxMenuItem *menuItem,
|
||||
bool checked, bool forCheckableItem)
|
||||
{
|
||||
// Under versions of Windows older than Vista we can't pass HBITMAP
|
||||
// directly as hbmpItem for 2 reasons:
|
||||
// 1. We can't draw it with transparency then (this is not
|
||||
// very important now but would be with themed menu bg)
|
||||
// 2. Worse, Windows inverts the bitmap for the selected
|
||||
// item and this looks downright ugly
|
||||
//
|
||||
// So we prefer to instead draw it ourselves in MSWOnDrawItem() by using
|
||||
// HBMMENU_CALLBACK for normal menu items when inserting it. And use
|
||||
// NULL for checkable menu items as hbmpChecked/hBmpUnchecked does not
|
||||
// support HBMMENU_CALLBACK.
|
||||
//
|
||||
// However under Vista using HBMMENU_CALLBACK causes the entire menu to be
|
||||
// drawn using the classic theme instead of the current one and it does
|
||||
// handle transparency just fine so do use the real bitmap there
|
||||
#if wxUSE_IMAGE
|
||||
if ( wxGetWinVersion() >= wxWinVersion_Vista )
|
||||
{
|
||||
wxBitmap bmp = menuItem->GetBitmap(checked);
|
||||
if ( bmp.IsOk() )
|
||||
{
|
||||
// we must use PARGB DIB for the menu bitmaps so ensure that we do
|
||||
wxImage img(bmp.ConvertToImage());
|
||||
if ( !img.HasAlpha() )
|
||||
{
|
||||
img.InitAlpha();
|
||||
menuItem->SetBitmap(img, checked);
|
||||
}
|
||||
|
||||
return GetHbitmapOf(menuItem->GetBitmap(checked));
|
||||
}
|
||||
//else: bitmap is not set
|
||||
return NULL;
|
||||
}
|
||||
#endif // wxUSE_IMAGE
|
||||
|
||||
return forCheckableItem ? NULL : HBMMENU_CALLBACK;
|
||||
}
|
||||
|
||||
// helper function for draw coloured check mark
|
||||
void DrawColorCheckMark(HDC hdc, int x, int y, int cx, int cy, HDC hdcCheckMask, int idxColor)
|
||||
{
|
||||
@@ -1376,44 +1422,17 @@ bool wxMenuItem::MSWMustUseOwnerDrawn()
|
||||
|
||||
#endif // wxUSE_OWNER_DRAWN
|
||||
|
||||
// returns the HBITMAP to use in MENUITEMINFO
|
||||
// returns the HBITMAP to use in MENUITEMINFO for hBmpItem member
|
||||
HBITMAP wxMenuItem::GetHBitmapForMenu(bool checked)
|
||||
{
|
||||
// Under versions of Windows older than Vista we can't pass HBITMAP
|
||||
// directly as hbmpItem for 2 reasons:
|
||||
// 1. We can't draw it with transparency then (this is not
|
||||
// very important now but would be with themed menu bg)
|
||||
// 2. Worse, Windows inverts the bitmap for the selected
|
||||
// item and this looks downright ugly
|
||||
//
|
||||
// So we prefer to instead draw it ourselves in MSWOnDrawItem().by using
|
||||
// HBMMENU_CALLBACK when inserting it
|
||||
//
|
||||
// However under Vista using HBMMENU_CALLBACK causes the entire menu to be
|
||||
// drawn using the classic theme instead of the current one and it does
|
||||
// handle transparency just fine so do use the real bitmap there
|
||||
#if wxUSE_IMAGE
|
||||
if ( wxGetWinVersion() >= wxWinVersion_Vista )
|
||||
{
|
||||
wxBitmap bmp = GetBitmap(checked);
|
||||
if ( bmp.IsOk() )
|
||||
{
|
||||
// we must use PARGB DIB for the menu bitmaps so ensure that we do
|
||||
wxImage img(bmp.ConvertToImage());
|
||||
if ( !img.HasAlpha() )
|
||||
{
|
||||
img.InitAlpha();
|
||||
SetBitmap(img, checked);
|
||||
}
|
||||
return ::DoGetHBitmapForMenu(this, checked, false /*for checkable item?*/);
|
||||
}
|
||||
|
||||
return GetHbitmapOf(GetBitmap(checked));
|
||||
}
|
||||
//else: bitmap is not set
|
||||
return NULL;
|
||||
}
|
||||
#endif // wxUSE_IMAGE
|
||||
|
||||
return HBMMENU_CALLBACK;
|
||||
// returns the HBITMAP to use in MENUITEMINFO for hbmpChecked and
|
||||
// hbmpUnchecked member
|
||||
HBITMAP wxMenuItem::GetHBitmapForMenuCheckable(bool checked)
|
||||
{
|
||||
return ::DoGetHBitmapForMenu(this, checked, true /*for checkable item?*/);
|
||||
}
|
||||
|
||||
int wxMenuItem::MSGetMenuItemPos() const
|
||||
|
Reference in New Issue
Block a user