wxBitmapBundle for wxMenuItem on MSW

This commit is contained in:
Alexander Koshelev
2022-01-28 16:28:18 +03:00
parent e5e9794607
commit 27be2ed641
6 changed files with 130 additions and 42 deletions

View File

@@ -69,6 +69,12 @@ public:
// containing this position. // containing this position.
bool MSWGetRadioGroupRange(int pos, int *start, int *end) const; bool MSWGetRadioGroupRange(int pos, int *start, int *end) const;
#if wxUSE_MENUBAR
virtual void Attach(wxMenuBarBase *menubar) wxOVERRIDE;
#endif
void SetupBitmaps();
#if wxUSE_ACCEL #if wxUSE_ACCEL
// called by wxMenuBar to build its accel table from the accels of all menus // called by wxMenuBar to build its accel table from the accels of all menus
bool HasAccels() const { return !m_accels.empty(); } bool HasAccels() const { return !m_accels.empty(); }
@@ -220,6 +226,16 @@ protected:
// common part of all ctors // common part of all ctors
void Init(); void Init();
void SetupBitmaps();
void OnDPIChanged(wxDPIChangedEvent& event)
{
// need to reset bitmaps
SetupBitmaps();
event.Skip();
}
WXHMENU m_hMenu; WXHMENU m_hMenu;
// Return the MSW position for a wxMenu which is sometimes different from // Return the MSW position for a wxMenu which is sometimes different from

View File

@@ -15,7 +15,7 @@
// headers // headers
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
#include "wx/bitmap.h" #include "wx/bmpbndl.h"
#if wxUSE_OWNER_DRAWN #if wxUSE_OWNER_DRAWN
#include "wx/ownerdrw.h" #include "wx/ownerdrw.h"
@@ -73,30 +73,30 @@ public:
); );
#endif #endif
void SetBitmaps(const wxBitmap& bmpChecked, void SetBitmaps(const wxBitmapBundle& bmpChecked,
const wxBitmap& bmpUnchecked = wxNullBitmap) const wxBitmapBundle& bmpUnchecked = wxNullBitmap)
{ {
DoSetBitmap(bmpChecked, true); DoSetBitmap(bmpChecked, true);
DoSetBitmap(bmpUnchecked, false); DoSetBitmap(bmpUnchecked, false);
} }
void SetBitmap(const wxBitmap& bmp, bool bChecked = true) void SetBitmap(const wxBitmapBundle& bmp, bool bChecked = true)
{ {
DoSetBitmap(bmp, bChecked); DoSetBitmap(bmp, bChecked);
} }
const wxBitmap& GetBitmap(bool bChecked = true) const void SetupBitmaps();
{ return (bChecked ? m_bmpChecked : m_bmpUnchecked); }
wxBitmap GetBitmap(bool bChecked = true) const;
#if wxUSE_OWNER_DRAWN #if wxUSE_OWNER_DRAWN
void SetDisabledBitmap(const wxBitmap& bmpDisabled) void SetDisabledBitmap(const wxBitmapBundle& bmpDisabled)
{ {
m_bmpDisabled = bmpDisabled; m_bmpDisabled = bmpDisabled;
SetOwnerDrawn(true); SetOwnerDrawn(true);
} }
const wxBitmap& GetDisabledBitmap() const wxBitmap GetDisabledBitmap() const;
{ return m_bmpDisabled; }
int MeasureAccelWidth() const; int MeasureAccelWidth() const;
@@ -128,12 +128,14 @@ private:
WXHBITMAP GetHBitmapForMenu(BitmapKind kind) const; WXHBITMAP GetHBitmapForMenu(BitmapKind kind) const;
// helper function to set/change the bitmap // helper function to set/change the bitmap
void DoSetBitmap(const wxBitmap& bmp, bool bChecked); void DoSetBitmap(const wxBitmapBundle& bmp, bool bChecked);
private: private:
// common part of all ctors // common part of all ctors
void Init(); void Init();
wxBitmap GetBitmapFromBundle(const wxBitmapBundle& bundle) const;
// Return the item position in the menu containing it. // Return the item position in the menu containing it.
// //
// Returns -1 if the item is not attached to a menu or if we can't find its // Returns -1 if the item is not attached to a menu or if we can't find its
@@ -141,10 +143,10 @@ private:
int MSGetMenuItemPos() const; int MSGetMenuItemPos() const;
// item bitmaps // item bitmaps
wxBitmap m_bmpChecked, // bitmap to put near the item wxBitmapBundle m_bmpChecked, // bitmap to put near the item
m_bmpUnchecked; // (checked is used also for 'uncheckable' items) m_bmpUnchecked; // (checked is used also for 'uncheckable' items)
#if wxUSE_OWNER_DRAWN #if wxUSE_OWNER_DRAWN
wxBitmap m_bmpDisabled; wxBitmapBundle m_bmpDisabled;
#endif // wxUSE_OWNER_DRAWN #endif // wxUSE_OWNER_DRAWN
// Give wxMenu access to our MSWMustUseOwnerDrawn() and GetHBitmapForMenu(). // Give wxMenu access to our MSWMustUseOwnerDrawn() and GetHBitmapForMenu().

View File

@@ -559,7 +559,7 @@ MyFrame::MyFrame()
#if USE_LOG_WINDOW #if USE_LOG_WINDOW
wxMenuItem *item = new wxMenuItem(fileMenu, Menu_File_ClearLog, wxMenuItem *item = new wxMenuItem(fileMenu, Menu_File_ClearLog,
"Clear &log\tCtrl-L"); "Clear &log\tCtrl-L");
item->SetBitmap(copy_xpm); item->SetBitmap(wxBitmap(copy_xpm));
fileMenu->Append(item); fileMenu->Append(item);
fileMenu->AppendSeparator(); fileMenu->AppendSeparator();
#endif // USE_LOG_WINDOW #endif // USE_LOG_WINDOW

View File

@@ -305,6 +305,38 @@ bool wxMenu::MSWGetRadioGroupRange(int pos, int *start, int *end) const
return m_radioData && m_radioData->GetGroupRange(pos, start, end); return m_radioData && m_radioData->GetGroupRange(pos, start, end);
} }
#if wxUSE_MENUBAR
void wxMenu::Attach(wxMenuBarBase* menubar)
{
wxMenuBase::Attach(menubar);
if (menubar->IsAttached())
{
// menubar is already attached, we need to call SetupBitmaps
SetupBitmaps();
}
}
#endif
void wxMenu::SetupBitmaps()
{
for ( wxMenuItemList::compatibility_iterator node = m_items.GetFirst();
node;
node = node->GetNext() )
{
wxMenuItem *item = node->GetData();
if ( item->IsSubMenu() )
{
item->GetSubMenu()->SetupBitmaps();
}
if ( !item->IsSeparator() )
{
item->SetupBitmaps();
}
}
}
// append a new item or submenu to the menu // append a new item or submenu to the menu
bool wxMenu::DoInsertOrAppend(wxMenuItem *pItem, size_t pos) bool wxMenu::DoInsertOrAppend(wxMenuItem *pItem, size_t pos)
{ {
@@ -413,20 +445,6 @@ bool wxMenu::DoInsertOrAppend(wxMenuItem *pItem, size_t pos)
WinStruct<MENUITEMINFO> mii; WinStruct<MENUITEMINFO> mii;
mii.fMask = MIIM_STRING | MIIM_DATA; mii.fMask = MIIM_STRING | MIIM_DATA;
// don't set hbmpItem for the checkable items as it would
// be used for both checked and unchecked state
if ( pItem->IsCheckable() )
{
mii.fMask |= MIIM_CHECKMARKS;
mii.hbmpChecked = pItem->GetHBitmapForMenu(wxMenuItem::Checked);
mii.hbmpUnchecked = pItem->GetHBitmapForMenu(wxMenuItem::Unchecked);
}
else if ( pItem->GetBitmap().IsOk() )
{
mii.fMask |= MIIM_BITMAP;
mii.hbmpItem = pItem->GetHBitmapForMenu(wxMenuItem::Normal);
}
mii.cch = itemText.length(); mii.cch = itemText.length();
mii.dwTypeData = wxMSW_CONV_LPTSTR(itemText); mii.dwTypeData = wxMSW_CONV_LPTSTR(itemText);
@@ -593,6 +611,14 @@ bool wxMenu::DoInsertOrAppend(wxMenuItem *pItem, size_t pos)
// if we're already attached to the menubar, we must update it // if we're already attached to the menubar, we must update it
if ( IsAttached() && GetMenuBar()->IsAttached() ) if ( IsAttached() && GetMenuBar()->IsAttached() )
{ {
if ( pItem->IsSubMenu() )
{
pItem->GetSubMenu()->SetupBitmaps();
}
if ( !pItem->IsSeparator() )
{
pItem->SetupBitmaps();
}
GetMenuBar()->Refresh(); GetMenuBar()->Refresh();
} }
@@ -1233,6 +1259,14 @@ void wxMenuBar::RebuildAccelTable()
#endif // wxUSE_ACCEL #endif // wxUSE_ACCEL
void wxMenuBar::SetupBitmaps()
{
for ( wxMenuList::const_iterator it = m_menus.begin(); it != m_menus.end(); ++it )
{
(*it)->SetupBitmaps();
}
}
void wxMenuBar::Attach(wxFrame *frame) void wxMenuBar::Attach(wxFrame *frame)
{ {
wxMenuBarBase::Attach(frame); wxMenuBarBase::Attach(frame);
@@ -1240,6 +1274,10 @@ void wxMenuBar::Attach(wxFrame *frame)
#if wxUSE_ACCEL #if wxUSE_ACCEL
RebuildAccelTable(); RebuildAccelTable();
#endif // wxUSE_ACCEL #endif // wxUSE_ACCEL
SetupBitmaps();
frame->Bind(wxEVT_DPI_CHANGED, &wxMenuBar::OnDPIChanged, this);
} }
void wxMenuBar::Detach() void wxMenuBar::Detach()

View File

@@ -688,25 +688,50 @@ void wxMenuItem::SetItemLabel(const wxString& txt)
} }
} }
void wxMenuItem::DoSetBitmap(const wxBitmap& bmpNew, bool bChecked) wxBitmap wxMenuItem::GetBitmapFromBundle(const wxBitmapBundle& bundle) const
{ {
wxBitmap& bmp = bChecked ? m_bmpChecked : m_bmpUnchecked; if (bundle.IsOk())
if ( bmp.IsSameAs(bmpNew) ) {
return; if (m_parentMenu && m_parentMenu->GetWindow())
{
return bundle.GetBitmapFor(m_parentMenu->GetWindow());
}
else
{
return bundle.GetBitmap(wxDefaultSize);
}
}
return wxNullBitmap;
}
wxBitmap wxMenuItem::GetBitmap(bool bChecked) const
{
wxBitmap bmp = GetBitmapFromBundle(bChecked ? m_bmpChecked : m_bmpUnchecked);
#if wxUSE_IMAGE #if wxUSE_IMAGE
if ( !bmpNew.HasAlpha() && wxGetWinVersion() >= wxWinVersion_Vista) if ( bmp.IsOk() && !bmp.HasAlpha() && wxGetWinVersion() >= wxWinVersion_Vista)
{ {
// we must use PARGB DIB for the menu bitmaps so ensure that we do // we must use PARGB DIB for the menu bitmaps so ensure that we do
wxImage img(bmpNew.ConvertToImage()); wxImage img(bmp.ConvertToImage());
img.InitAlpha(); img.InitAlpha();
bmp = wxBitmap(img); bmp = wxBitmap(img);
} }
else
#endif // wxUSE_IMAGE #endif // wxUSE_IMAGE
{ return bmp;
bmp = bmpNew; }
}
#if wxUSE_OWNER_DRAWN
wxBitmap wxMenuItem::GetDisabledBitmap() const
{
return GetBitmapFromBundle(m_bmpDisabled);
}
#endif
void wxMenuItem::DoSetBitmap(const wxBitmapBundle& bmpNew, bool bChecked)
{
wxBitmapBundle& bmp = bChecked ? m_bmpChecked : m_bmpUnchecked;
if ( bmp.IsSameAs(bmpNew) )
return;
bmp = bmpNew;
#if wxUSE_OWNER_DRAWN #if wxUSE_OWNER_DRAWN
// already marked as owner-drawn, cannot be reverted // already marked as owner-drawn, cannot be reverted
@@ -738,7 +763,10 @@ void wxMenuItem::DoSetBitmap(const wxBitmap& bmpNew, bool bChecked)
return; return;
} }
#endif // wxUSE_OWNER_DRAWN #endif // wxUSE_OWNER_DRAWN
}
void wxMenuItem::SetupBitmaps()
{
const int itemPos = MSGetMenuItemPos(); const int itemPos = MSGetMenuItemPos();
if ( itemPos == -1 ) if ( itemPos == -1 )
{ {
@@ -855,8 +883,10 @@ bool wxMenuItem::OnMeasureItem(size_t *width, size_t *height)
{ {
// get size of bitmap always return valid value (0 for invalid bitmap), // get size of bitmap always return valid value (0 for invalid bitmap),
// so we don't needed check if bitmap is valid ;) // so we don't needed check if bitmap is valid ;)
size_t heightBmp = wxMax(m_bmpChecked.GetHeight(), m_bmpUnchecked.GetHeight()); wxBitmap bmpChecked = GetBitmap(true);
size_t widthBmp = wxMax(m_bmpChecked.GetWidth(), m_bmpUnchecked.GetWidth()); wxBitmap bmpUnchecked = GetBitmap(false);
size_t heightBmp = wxMax(bmpChecked.GetLogicalHeight(), bmpUnchecked.GetLogicalHeight());
size_t widthBmp = wxMax(bmpChecked.GetLogicalWidth(), bmpUnchecked.GetLogicalWidth());
if ( IsOwnerDrawn() ) if ( IsOwnerDrawn() )
{ {
@@ -1113,8 +1143,8 @@ bool wxMenuItem::OnDrawItem(wxDC& dc, const wxRect& rc,
dcMem.SelectObjectAsSource(bmp); dcMem.SelectObjectAsSource(bmp);
// center bitmap // center bitmap
int nBmpWidth = bmp.GetWidth(), int nBmpWidth = bmp.GetLogicalWidth(),
nBmpHeight = bmp.GetHeight(); nBmpHeight = bmp.GetLogicalHeight();
int x = rcImg.left + (imgWidth - nBmpWidth) / 2; int x = rcImg.left + (imgWidth - nBmpWidth) / 2;
int y = rcImg.top + (rcImg.bottom - rcImg.top - nBmpHeight) / 2; int y = rcImg.top + (rcImg.bottom - rcImg.top - nBmpHeight) / 2;

View File

@@ -2367,6 +2367,8 @@ static void wxYieldForCommandsOnly()
bool wxWindowMSW::DoPopupMenu(wxMenu *menu, int x, int y) bool wxWindowMSW::DoPopupMenu(wxMenu *menu, int x, int y)
{ {
menu->SetupBitmaps();
wxPoint pt; wxPoint pt;
if ( x == wxDefaultCoord && y == wxDefaultCoord ) if ( x == wxDefaultCoord && y == wxDefaultCoord )
{ {