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:
Dimitri Schoolwerth
2014-06-23 20:05:30 +00:00
parent 1697a45b1f
commit 6b12639c49
4 changed files with 91 additions and 40 deletions

View File

@@ -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);

View File

@@ -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"));

View File

@@ -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() )
{

View File

@@ -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