Fix calculation of the margins for owner-drawn menu items.

Take into account the widths of the bitmaps properly.

Closes #11268.

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@63222 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Vadim Zeitlin
2010-01-23 13:21:27 +00:00
parent 4e7c767fed
commit d08504dfa5
2 changed files with 176 additions and 102 deletions

View File

@@ -120,6 +120,14 @@ private:
wxAcceleratorArray m_accels; wxAcceleratorArray m_accels;
#endif // wxUSE_ACCEL #endif // wxUSE_ACCEL
#if wxUSE_OWNER_DRAWN
// true if the menu has any ownerdrawn items
bool m_ownerDrawn;
// the max width of menu items bitmaps
int m_maxBitmapWidth;
#endif // wxUSE_OWNER_DRAWN
DECLARE_DYNAMIC_CLASS_NO_COPY(wxMenu) DECLARE_DYNAMIC_CLASS_NO_COPY(wxMenu)
}; };

View File

@@ -106,7 +106,27 @@ void SetDefaultMenuItem(HMENU WXUNUSED_IN_WINCE(hmenu),
{ {
wxLogLastError(wxT("SetMenuItemInfo")); wxLogLastError(wxT("SetMenuItemInfo"));
} }
#endif #endif // !__WXWINCE__
}
// make the given menu item owner-drawn
void SetOwnerDrawnMenuItem(HMENU WXUNUSED_IN_WINCE(hmenu),
UINT WXUNUSED_IN_WINCE(id),
ULONG_PTR WXUNUSED_IN_WINCE(data))
{
#ifndef __WXWINCE__
MENUITEMINFO mii;
wxZeroMemory(mii);
mii.cbSize = sizeof(MENUITEMINFO);
mii.fMask = MIIM_FTYPE | MIIM_DATA;
mii.fType = MFT_OWNERDRAW;
mii.dwItemData = data;
if ( !::SetMenuItemInfo(hmenu, id, FALSE, &mii) )
{
wxLogLastError(wxT("SetMenuItemInfo"));
}
#endif // !__WXWINCE__
} }
#ifdef __WXWINCE__ #ifdef __WXWINCE__
@@ -125,7 +145,7 @@ UINT GetMenuState(HMENU hMenu, UINT id, UINT flags)
} }
#endif // __WXWINCE__ #endif // __WXWINCE__
bool IsLessThanStdSize(const wxBitmap& bmp) inline bool IsLessThanStdSize(const wxBitmap& bmp)
{ {
// FIXME: these +4 are chosen so that 16*16 bitmaps pass this test with // FIXME: these +4 are chosen so that 16*16 bitmaps pass this test with
// default SM_CXMENUCHECK value but I have no idea what do we really // default SM_CXMENUCHECK value but I have no idea what do we really
@@ -244,6 +264,11 @@ void wxMenu::Init()
m_doBreak = false; m_doBreak = false;
m_startRadioGroup = -1; m_startRadioGroup = -1;
#if wxUSE_OWNER_DRAWN
m_ownerDrawn = false;
m_maxBitmapWidth = 0;
#endif // wxUSE_OWNER_DRAWN
// create the menu // create the menu
m_hMenu = (WXHMENU)CreatePopupMenu(); m_hMenu = (WXHMENU)CreatePopupMenu();
if ( !m_hMenu ) if ( !m_hMenu )
@@ -470,25 +495,9 @@ bool wxMenu::DoInsertOrAppend(wxMenuItem *pItem, size_t pos)
#if wxUSE_OWNER_DRAWN #if wxUSE_OWNER_DRAWN
// Under older systems mixing owner-drawn and non-owner-drawn items results // Under older systems mixing owner-drawn and non-owner-drawn items results
// in inconsistent margins, so we force this one to be owner-drawn if any // in inconsistent margins, so we force this one to be owner-drawn if any
// other items already are. Later we might want to use a boolean in the // other items already are.
// wxMenu to avoid search. Also we might make this fix unnecessary by if ( m_ownerDrawn && !pItem->IsSeparator() )
// getting the correct margin using NONCLIENTMETRICS.
static const wxWinVersion winver = wxGetWinVersion();
if ( winver < wxWinVersion_XP &&
!pItem->IsOwnerDrawn() && !pItem->IsSeparator() )
{
// Check if any other items are ownerdrawn, and make ownerdrawn if so
wxMenuItemList::compatibility_iterator node = GetMenuItems().GetFirst();
while (node)
{
if (node->GetData()->IsOwnerDrawn())
{
pItem->SetOwnerDrawn(true); pItem->SetOwnerDrawn(true);
break;
}
node = node->GetNext();
}
}
#endif // wxUSE_OWNER_DRAWN #endif // wxUSE_OWNER_DRAWN
// check if we have something more than a simple text item // check if we have something more than a simple text item
@@ -496,17 +505,23 @@ bool wxMenu::DoInsertOrAppend(wxMenuItem *pItem, size_t pos)
if ( pItem->IsOwnerDrawn() ) if ( pItem->IsOwnerDrawn() )
{ {
#ifndef __DMC__ #ifndef __DMC__
if ( !m_ownerDrawn )
{
// MIIM_BITMAP only works under WinME/2000+ so we always use owner // MIIM_BITMAP only works under WinME/2000+ so we always use owner
// drawn item under the previous versions and we also have to use them // drawn item under the previous versions and we also have to use
// in any case if the item has custom colours or font // them in any case if the item has custom colours or font
static const wxWinVersion winver = wxGetWinVersion();
bool mustUseOwnerDrawn = winver < wxWinVersion_98 || bool mustUseOwnerDrawn = winver < wxWinVersion_98 ||
pItem->GetTextColour().Ok() || pItem->GetTextColour().Ok() ||
pItem->GetBackgroundColour().Ok() || pItem->GetBackgroundColour().Ok() ||
pItem->GetFont().Ok(); pItem->GetFont().Ok();
if ( !mustUseOwnerDrawn ) if ( !mustUseOwnerDrawn )
{ {
const wxBitmap& bmpUnchecked = pItem->GetBitmap(false), const wxBitmap& bmpUnchecked = pItem->GetBitmap(false),
bmpChecked = pItem->GetBitmap(true); bmpChecked = pItem->GetBitmap(true);
if ( (bmpUnchecked.Ok() && !IsLessThanStdSize(bmpUnchecked)) || if ( (bmpUnchecked.Ok() && !IsLessThanStdSize(bmpUnchecked)) ||
(bmpChecked.Ok() && !IsLessThanStdSize(bmpChecked)) ) (bmpChecked.Ok() && !IsLessThanStdSize(bmpChecked)) )
{ {
@@ -514,8 +529,8 @@ bool wxMenu::DoInsertOrAppend(wxMenuItem *pItem, size_t pos)
} }
} }
// use InsertMenuItem() if possible as it's guaranteed to look correct // use InsertMenuItem() if possible as it's guaranteed to look
// while our owner-drawn code is not // correct while our owner-drawn code is not
if ( !mustUseOwnerDrawn ) if ( !mustUseOwnerDrawn )
{ {
WinStruct<MENUITEMINFO> mii; WinStruct<MENUITEMINFO> mii;
@@ -585,6 +600,7 @@ bool wxMenu::DoInsertOrAppend(wxMenuItem *pItem, size_t pos)
pItem->SetOwnerDrawn(false); pItem->SetOwnerDrawn(false);
} }
} }
}
#endif // __DMC__ #endif // __DMC__
if ( !ok ) if ( !ok )
@@ -592,6 +608,56 @@ bool wxMenu::DoInsertOrAppend(wxMenuItem *pItem, size_t pos)
// item draws itself, pass pointer to it in data parameter // item draws itself, pass pointer to it in data parameter
flags |= MF_OWNERDRAW; flags |= MF_OWNERDRAW;
pData = (LPCTSTR)pItem; pData = (LPCTSTR)pItem;
bool updateAllMargins = false;
// get size of bitmap always return valid value (0 for invalid bitmap),
// so we don't needed check if bitmap is valid ;)
int uncheckedW = pItem->GetBitmap(false).GetWidth();
int checkedW = pItem->GetBitmap(true).GetWidth();
if ( m_maxBitmapWidth < uncheckedW )
{
m_maxBitmapWidth = uncheckedW;
updateAllMargins = true;
}
if ( m_maxBitmapWidth < checkedW )
{
m_maxBitmapWidth = checkedW;
updateAllMargins = true;
}
// make other item ownerdrawn and update margin width for equals alignment
if ( !m_ownerDrawn || updateAllMargins )
{
wxMenuItemList::compatibility_iterator node = GetMenuItems().GetFirst();
while (node)
{
wxMenuItem* item = node->GetData();
if ( !item->IsSeparator() )
{
if ( !item->IsOwnerDrawn() )
{
item->SetOwnerDrawn(true);
SetOwnerDrawnMenuItem(GetHmenu(), item->GetMSWId(),
reinterpret_cast<ULONG_PTR>(item));
}
item->SetMarginWidth(m_maxBitmapWidth);
}
node = node->GetNext();
}
// set menu as ownerdrawn
m_ownerDrawn = true;
}
// only update our margin for equals alignment to other item
else if ( !updateAllMargins )
{
pItem->SetMarginWidth(m_maxBitmapWidth);
}
} }
} }
else else