diff --git a/include/wx/msw/menuitem.h b/include/wx/msw/menuitem.h index 741addbcc7..4362d621e6 100644 --- a/include/wx/msw/menuitem.h +++ b/include/wx/msw/menuitem.h @@ -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); diff --git a/samples/menu/menu.cpp b/samples/menu/menu.cpp index f02168fbf8..3afe190faf 100644 --- a/samples/menu/menu.cpp +++ b/samples/menu/menu.cpp @@ -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")); diff --git a/src/msw/menu.cpp b/src/msw/menu.cpp index acc9e48867..ee4e49936d 100644 --- a/src/msw/menu.cpp +++ b/src/msw/menu.cpp @@ -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() ) { diff --git a/src/msw/menuitem.cpp b/src/msw/menuitem.cpp index a6593f35ed..62d7922cf3 100644 --- a/src/msw/menuitem.cpp +++ b/src/msw/menuitem.cpp @@ -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