support not-quite-owner-drawn mode when we draw only the bitmap and the system takes care of the rest
git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@34576 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
@@ -40,7 +40,7 @@ public:
|
|||||||
wxOwnerDrawn(const wxString& str = wxEmptyString,
|
wxOwnerDrawn(const wxString& str = wxEmptyString,
|
||||||
bool bCheckable = false,
|
bool bCheckable = false,
|
||||||
bool bMenuItem = false); // FIXME kludge for colors
|
bool bMenuItem = false); // FIXME kludge for colors
|
||||||
virtual ~wxOwnerDrawn() { }
|
virtual ~wxOwnerDrawn();
|
||||||
|
|
||||||
// fix appearance
|
// fix appearance
|
||||||
void SetFont(const wxFont& font)
|
void SetFont(const wxFont& font)
|
||||||
@@ -142,6 +142,13 @@ public:
|
|||||||
virtual bool OnDrawItem(wxDC& dc, const wxRect& rc, wxODAction act, wxODStatus stat);
|
virtual bool OnDrawItem(wxDC& dc, const wxRect& rc, wxODAction act, wxODStatus stat);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
// return true if this is a menu item
|
||||||
|
bool IsMenuItem() const;
|
||||||
|
|
||||||
|
// get the font to use, whether m_font is set or not
|
||||||
|
wxFont GetFontToUse() const;
|
||||||
|
|
||||||
|
|
||||||
wxString m_strName, // label for a manu item
|
wxString m_strName, // label for a manu item
|
||||||
m_strAccel; // the accel string ("Ctrl-F17") if any
|
m_strAccel; // the accel string ("Ctrl-F17") if any
|
||||||
|
|
||||||
|
@@ -96,6 +96,18 @@ bool wxMSWSystemMenuFontModule::ms_showCues = true;
|
|||||||
|
|
||||||
IMPLEMENT_DYNAMIC_CLASS(wxMSWSystemMenuFontModule, wxModule)
|
IMPLEMENT_DYNAMIC_CLASS(wxMSWSystemMenuFontModule, wxModule)
|
||||||
|
|
||||||
|
|
||||||
|
// temporary hack to implement wxOwnerDrawn::IsMenuItem() without breaking
|
||||||
|
// backwards compatibility
|
||||||
|
#if wxCHECK_VERSION(2, 7, 0)
|
||||||
|
#pragma warning "TODO: remove gs_menuItems hack"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "wx/hashset.h"
|
||||||
|
WX_DECLARE_HASH_SET(wxOwnerDrawn*, wxPointerHash, wxPointerEqual, OwnerDrawnSet);
|
||||||
|
|
||||||
|
static OwnerDrawnSet gs_menuItems;
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
// implementation of wxOwnerDrawn class
|
// implementation of wxOwnerDrawn class
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
@@ -103,32 +115,17 @@ IMPLEMENT_DYNAMIC_CLASS(wxMSWSystemMenuFontModule, wxModule)
|
|||||||
// ctor
|
// ctor
|
||||||
// ----
|
// ----
|
||||||
wxOwnerDrawn::wxOwnerDrawn(const wxString& str,
|
wxOwnerDrawn::wxOwnerDrawn(const wxString& str,
|
||||||
bool bCheckable, bool bMenuItem)
|
bool bCheckable,
|
||||||
|
bool bMenuItem)
|
||||||
: m_strName(str)
|
: m_strName(str)
|
||||||
{
|
{
|
||||||
// get the default menu height and font from the system
|
|
||||||
NONCLIENTMETRICS nm;
|
|
||||||
nm.cbSize = sizeof (NONCLIENTMETRICS);
|
|
||||||
SystemParametersInfo (SPI_GETNONCLIENTMETRICS,0,&nm,0);
|
|
||||||
m_nMinHeight = nm.iMenuHeight;
|
|
||||||
|
|
||||||
// nm.iMenuWidth is the system default for the width of
|
|
||||||
// menu icons and checkmarks
|
|
||||||
if (ms_nDefaultMarginWidth == 0)
|
if (ms_nDefaultMarginWidth == 0)
|
||||||
{
|
{
|
||||||
ms_nDefaultMarginWidth = ::GetSystemMetrics(SM_CXMENUCHECK) + wxSystemSettings::GetMetric(wxSYS_EDGE_X);
|
ms_nDefaultMarginWidth = ::GetSystemMetrics(SM_CXMENUCHECK) +
|
||||||
|
wxSystemSettings::GetMetric(wxSYS_EDGE_X);
|
||||||
ms_nLastMarginWidth = ms_nDefaultMarginWidth;
|
ms_nLastMarginWidth = ms_nDefaultMarginWidth;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (wxMSWSystemMenuFontModule::ms_systemMenuFont->Ok() && bMenuItem)
|
|
||||||
{
|
|
||||||
m_font = *wxMSWSystemMenuFontModule::ms_systemMenuFont;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
m_font = *wxNORMAL_FONT;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_bCheckable = bCheckable;
|
m_bCheckable = bCheckable;
|
||||||
m_bOwnerDrawn = false;
|
m_bOwnerDrawn = false;
|
||||||
m_nHeight = 0;
|
m_nHeight = 0;
|
||||||
@@ -136,6 +133,25 @@ wxOwnerDrawn::wxOwnerDrawn(const wxString& str,
|
|||||||
m_nMinHeight = wxMSWSystemMenuFontModule::ms_systemMenuHeight;
|
m_nMinHeight = wxMSWSystemMenuFontModule::ms_systemMenuHeight;
|
||||||
|
|
||||||
m_bmpDisabled = wxNullBitmap;
|
m_bmpDisabled = wxNullBitmap;
|
||||||
|
|
||||||
|
// TODO: we can't add new m_isMenuItem field in 2.6, so we use this hack
|
||||||
|
// with the map, but do add m_isMenuItem in 2.7
|
||||||
|
if ( bMenuItem )
|
||||||
|
{
|
||||||
|
gs_menuItems.insert(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
wxOwnerDrawn::~wxOwnerDrawn()
|
||||||
|
{
|
||||||
|
// TODO: remove this in 2.7
|
||||||
|
gs_menuItems.erase(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool wxOwnerDrawn::IsMenuItem() const
|
||||||
|
{
|
||||||
|
// TODO: in 2.7, replace this with simple "return m_isMenuItem"
|
||||||
|
return gs_menuItems.count(this) == 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -149,62 +165,88 @@ size_t wxOwnerDrawn::ms_nLastMarginWidth = 0;
|
|||||||
// drawing
|
// drawing
|
||||||
// -------
|
// -------
|
||||||
|
|
||||||
|
wxFont wxOwnerDrawn::GetFontToUse() const
|
||||||
|
{
|
||||||
|
wxFont font = m_font;
|
||||||
|
if ( !font.Ok() )
|
||||||
|
{
|
||||||
|
if ( IsMenuItem() )
|
||||||
|
font = *wxMSWSystemMenuFontModule::ms_systemMenuFont;
|
||||||
|
|
||||||
|
if ( !font.Ok() )
|
||||||
|
font = *wxNORMAL_FONT;
|
||||||
|
}
|
||||||
|
|
||||||
|
return font;
|
||||||
|
}
|
||||||
|
|
||||||
// get size of the item
|
// get size of the item
|
||||||
// The item size includes the menu string, the accel string,
|
// The item size includes the menu string, the accel string,
|
||||||
// the bitmap and size for a submenu expansion arrow...
|
// the bitmap and size for a submenu expansion arrow...
|
||||||
bool wxOwnerDrawn::OnMeasureItem(size_t *pwidth, size_t *pheight)
|
bool wxOwnerDrawn::OnMeasureItem(size_t *pwidth, size_t *pheight)
|
||||||
{
|
{
|
||||||
wxMemoryDC dc;
|
if ( IsOwnerDrawn() )
|
||||||
|
{
|
||||||
|
wxMemoryDC dc;
|
||||||
|
|
||||||
wxString str = wxStripMenuCodes(m_strName);
|
wxString str = wxStripMenuCodes(m_strName);
|
||||||
|
|
||||||
// if we have a valid accel string, then pad out
|
// if we have a valid accel string, then pad out
|
||||||
// the menu string so that the menu and accel string are not
|
// the menu string so that the menu and accel string are not
|
||||||
// placed on top of each other.
|
// placed on top of each other.
|
||||||
if ( !m_strAccel.empty() )
|
if ( !m_strAccel.empty() )
|
||||||
{
|
{
|
||||||
str.Pad(str.Length()%8);
|
str.Pad(str.Length()%8);
|
||||||
str += m_strAccel;
|
str += m_strAccel;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_font.Ok())
|
dc.SetFont(GetFontToUse());
|
||||||
dc.SetFont(GetFont());
|
|
||||||
|
|
||||||
dc.GetTextExtent(str, (long *)pwidth, (long *)pheight);
|
dc.GetTextExtent(str, (long *)pwidth, (long *)pheight);
|
||||||
|
|
||||||
// increase size to accommodate bigger bitmaps if necessary
|
// add space at the end of the menu for the submenu expansion arrow
|
||||||
if (m_bmpChecked.Ok())
|
// this will also allow offsetting the accel string from the right edge
|
||||||
{
|
*pwidth += GetMarginWidth() + 16;
|
||||||
// Is BMP height larger then text height?
|
}
|
||||||
size_t adjustedHeight = m_bmpChecked.GetHeight() +
|
else // don't draw the text, just the bitmap (if any)
|
||||||
2*wxSystemSettings::GetMetric(wxSYS_EDGE_Y);
|
{
|
||||||
if (*pheight < adjustedHeight)
|
*pwidth =
|
||||||
*pheight = adjustedHeight;
|
*pheight = 0;
|
||||||
|
}
|
||||||
|
|
||||||
// Does BMP encroach on default check menu position?
|
// increase size to accommodate bigger bitmaps if necessary
|
||||||
size_t adjustedWidth = m_bmpChecked.GetWidth();
|
if (m_bmpChecked.Ok())
|
||||||
|
{
|
||||||
|
// Is BMP height larger then text height?
|
||||||
|
size_t adjustedHeight = m_bmpChecked.GetHeight() +
|
||||||
|
2*wxSystemSettings::GetMetric(wxSYS_EDGE_Y);
|
||||||
|
if (*pheight < adjustedHeight)
|
||||||
|
*pheight = adjustedHeight;
|
||||||
|
|
||||||
// Do we need to widen margin to fit BMP?
|
const size_t widthBmp = m_bmpChecked.GetWidth();
|
||||||
if ((size_t)GetMarginWidth() < adjustedWidth)
|
if ( IsOwnerDrawn() )
|
||||||
SetMarginWidth(adjustedWidth);
|
{
|
||||||
}
|
// widen the margin to fit the bitmap if necessary
|
||||||
|
if ((size_t)GetMarginWidth() < widthBmp)
|
||||||
|
SetMarginWidth(widthBmp);
|
||||||
|
}
|
||||||
|
else // we must allocate enough space for the bitmap
|
||||||
|
{
|
||||||
|
*pwidth += widthBmp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// add space at the end of the menu for the submenu expansion arrow
|
// add a 4-pixel separator, otherwise menus look cluttered
|
||||||
// this will also allow offsetting the accel string from the right edge
|
*pwidth += 4;
|
||||||
*pwidth += GetMarginWidth() + 16;
|
|
||||||
|
|
||||||
// add a 4-pixel separator, otherwise menus look cluttered
|
// make sure that this item is at least as tall as the system menu height
|
||||||
*pwidth += 4;
|
if ( *pheight < m_nMinHeight )
|
||||||
|
*pheight = m_nMinHeight;
|
||||||
|
|
||||||
// make sure that this item is at least as
|
// remember height for use in OnDrawItem
|
||||||
// tall as the user's system settings specify
|
m_nHeight = *pheight;
|
||||||
if (*pheight < m_nMinHeight)
|
|
||||||
*pheight = m_nMinHeight;
|
|
||||||
|
|
||||||
// remember height for use in OnDrawItem
|
return true;
|
||||||
m_nHeight = *pheight;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// draw the item
|
// draw the item
|
||||||
@@ -280,69 +322,61 @@ bool wxOwnerDrawn::OnDrawItem(wxDC& dc,
|
|||||||
|
|
||||||
|
|
||||||
// using native API because it recognizes '&'
|
// using native API because it recognizes '&'
|
||||||
int nPrevMode = SetBkMode(hdc, TRANSPARENT);
|
if ( IsOwnerDrawn() )
|
||||||
HBRUSH hbr = CreateSolidBrush(colBack),
|
|
||||||
hPrevBrush = (HBRUSH)SelectObject(hdc, hbr);
|
|
||||||
|
|
||||||
RECT rectFill = { rc.GetLeft(), rc.GetTop(),
|
|
||||||
rc.GetRight() + 1, rc.GetBottom() + 1 };
|
|
||||||
|
|
||||||
if ( (st & wxODSelected) && m_bmpChecked.Ok() && draw_bitmap_edge ) {
|
|
||||||
// only draw the highlight under the text, not under
|
|
||||||
// the bitmap or checkmark
|
|
||||||
rectFill.left = xText;
|
|
||||||
}
|
|
||||||
|
|
||||||
FillRect(hdc, &rectFill, hbr);
|
|
||||||
|
|
||||||
// use default font if no font set
|
|
||||||
HFONT hfont;
|
|
||||||
if ( m_font.Ok() ) {
|
|
||||||
m_font.RealizeResource();
|
|
||||||
hfont = (HFONT)m_font.GetResourceHandle();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
hfont = (HFONT)::GetStockObject(SYSTEM_FONT);
|
|
||||||
}
|
|
||||||
|
|
||||||
HFONT hPrevFont = (HFONT) ::SelectObject(hdc, hfont);
|
|
||||||
|
|
||||||
wxString strMenuText = m_strName.BeforeFirst('\t');
|
|
||||||
|
|
||||||
xText += 3; // separate text from the highlight rectangle
|
|
||||||
|
|
||||||
SIZE sizeRect;
|
|
||||||
::GetTextExtentPoint32(hdc, strMenuText.c_str(), strMenuText.Length(), &sizeRect);
|
|
||||||
::DrawState(hdc, NULL, NULL,
|
|
||||||
(LPARAM)strMenuText.c_str(), strMenuText.length(),
|
|
||||||
xText, rc.y + (int) ((rc.GetHeight()-sizeRect.cy)/2.0), // centre text vertically
|
|
||||||
rc.GetWidth()-margin, sizeRect.cy,
|
|
||||||
DST_PREFIXTEXT |
|
|
||||||
(((st & wxODDisabled) && !(st & wxODSelected)) ? DSS_DISABLED : 0) |
|
|
||||||
(((st & wxODHidePrefix) && !wxMSWSystemMenuFontModule::ms_showCues) ? 512 : 0)); // 512 == DSS_HIDEPREFIX
|
|
||||||
|
|
||||||
// ::SetTextAlign(hdc, TA_RIGHT) doesn't work with DSS_DISABLED or DSS_MONO
|
|
||||||
// as the last parameter in DrawState() (at least with Windows98). So we have
|
|
||||||
// to take care of right alignment ourselves.
|
|
||||||
if ( !m_strAccel.empty() )
|
|
||||||
{
|
{
|
||||||
int accel_width, accel_height;
|
int nPrevMode = SetBkMode(hdc, TRANSPARENT);
|
||||||
dc.GetTextExtent(m_strAccel, &accel_width, &accel_height);
|
AutoHBRUSH hbr(colBack);
|
||||||
// right align accel string with right edge of menu ( offset by the
|
SelectInHDC selBrush(hdc, hbr);
|
||||||
// margin width )
|
|
||||||
::DrawState(hdc, NULL, NULL,
|
RECT rectFill = { rc.GetLeft(), rc.GetTop(),
|
||||||
(LPARAM)m_strAccel.c_str(), m_strAccel.length(),
|
rc.GetRight() + 1, rc.GetBottom() + 1 };
|
||||||
rc.GetWidth()-16-accel_width, rc.y+(int) ((rc.GetHeight()-sizeRect.cy)/2.0),
|
|
||||||
0, 0,
|
if ( (st & wxODSelected) && m_bmpChecked.Ok() && draw_bitmap_edge ) {
|
||||||
DST_TEXT |
|
// only draw the highlight under the text, not under
|
||||||
(((st & wxODDisabled) && !(st & wxODSelected)) ? DSS_DISABLED : 0));
|
// the bitmap or checkmark
|
||||||
|
rectFill.left = xText;
|
||||||
|
}
|
||||||
|
|
||||||
|
FillRect(hdc, &rectFill, hbr);
|
||||||
|
|
||||||
|
// use default font if no font set
|
||||||
|
wxFont fontToUse = GetFontToUse();
|
||||||
|
SelectInHDC selFont(hdc, GetHfontOf(fontToUse));
|
||||||
|
|
||||||
|
wxString strMenuText = m_strName.BeforeFirst('\t');
|
||||||
|
|
||||||
|
xText += 3; // separate text from the highlight rectangle
|
||||||
|
|
||||||
|
SIZE sizeRect;
|
||||||
|
::GetTextExtentPoint32(hdc, strMenuText.c_str(), strMenuText.Length(), &sizeRect);
|
||||||
|
::DrawState(hdc, NULL, NULL,
|
||||||
|
(LPARAM)strMenuText.c_str(), strMenuText.length(),
|
||||||
|
xText, rc.y + (int) ((rc.GetHeight()-sizeRect.cy)/2.0), // centre text vertically
|
||||||
|
rc.GetWidth()-margin, sizeRect.cy,
|
||||||
|
DST_PREFIXTEXT |
|
||||||
|
(((st & wxODDisabled) && !(st & wxODSelected)) ? DSS_DISABLED : 0) |
|
||||||
|
(((st & wxODHidePrefix) && !wxMSWSystemMenuFontModule::ms_showCues) ? 512 : 0)); // 512 == DSS_HIDEPREFIX
|
||||||
|
|
||||||
|
// ::SetTextAlign(hdc, TA_RIGHT) doesn't work with DSS_DISABLED or DSS_MONO
|
||||||
|
// as the last parameter in DrawState() (at least with Windows98). So we have
|
||||||
|
// to take care of right alignment ourselves.
|
||||||
|
if ( !m_strAccel.empty() )
|
||||||
|
{
|
||||||
|
int accel_width, accel_height;
|
||||||
|
dc.GetTextExtent(m_strAccel, &accel_width, &accel_height);
|
||||||
|
// right align accel string with right edge of menu ( offset by the
|
||||||
|
// margin width )
|
||||||
|
::DrawState(hdc, NULL, NULL,
|
||||||
|
(LPARAM)m_strAccel.c_str(), m_strAccel.length(),
|
||||||
|
rc.GetWidth()-16-accel_width, rc.y+(int) ((rc.GetHeight()-sizeRect.cy)/2.0),
|
||||||
|
0, 0,
|
||||||
|
DST_TEXT |
|
||||||
|
(((st & wxODDisabled) && !(st & wxODSelected)) ? DSS_DISABLED : 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
(void)SetBkMode(hdc, nPrevMode);
|
||||||
}
|
}
|
||||||
|
|
||||||
(void)SelectObject(hdc, hPrevBrush);
|
|
||||||
(void)SelectObject(hdc, hPrevFont);
|
|
||||||
(void)SetBkMode(hdc, nPrevMode);
|
|
||||||
|
|
||||||
DeleteObject(hbr);
|
|
||||||
|
|
||||||
// draw the bitmap
|
// draw the bitmap
|
||||||
// ---------------
|
// ---------------
|
||||||
|
Reference in New Issue
Block a user