Improve disabled buttons appearance in wxMSW when not using themes.

Owner drawn buttons were not drawn in the same way as normal ones when they
were disabled, use Win32 DrawState() to do it now to achieve the correct
appearance.

Closes #11746.

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@75908 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Vadim Zeitlin 2014-02-17 23:53:25 +00:00
parent 99d3a4f4d2
commit fd743aad4b

View File

@ -831,56 +831,137 @@ void DrawButtonText(HDC hdc,
{
const wxString text = btn->GetLabel();
if ( text.find(wxT('\n')) != wxString::npos )
// To get a native look for owner-drawn button in disabled state (without
// theming) we must use DrawState() to draw the text label.
if ( !wxUxThemeEngine::GetIfActive() && !btn->IsEnabled() )
{
// draw multiline label
// However using DrawState() has some drawbacks:
// 1. It generally doesn't support alignment flags (except right
// alignment), so we need to align the text on our own.
// 2. It doesn't support multliline texts and there is necessary to
// draw/align multiline text line by line.
// center text horizontally in any case
flags |= DT_CENTER;
// first we need to compute its bounding rect
// Compute bounding rect for the whole text.
RECT rc;
::CopyRect(&rc, pRect);
::DrawText(hdc, text.t_str(), text.length(), &rc,
DT_CENTER | DT_CALCRECT);
::SetRectEmpty(&rc);
::DrawText(hdc, text.t_str(), text.length(), &rc, DT_CALCRECT);
// now center this rect inside the entire button area
const LONG w = rc.right - rc.left;
const LONG h = rc.bottom - rc.top;
rc.left = pRect->left + (pRect->right - pRect->left)/2 - w/2;
rc.right = rc.left+w;
rc.top = pRect->top + (pRect->bottom - pRect->top)/2 - h/2;
rc.bottom = rc.top+h;
::DrawText(hdc, text.t_str(), text.length(), &rc, flags);
}
else // single line label
{
// translate wx button flags to alignment flags for DrawText()
if ( btn->HasFlag(wxBU_RIGHT) )
{
flags |= DT_RIGHT;
}
else if ( !btn->HasFlag(wxBU_LEFT) )
{
flags |= DT_CENTER;
}
//else: DT_LEFT is the default anyhow (and its value is 0 too)
// Based on wxButton flags determine bottom edge of the drawing rect
// inside the entire button area.
int y0;
if ( btn->HasFlag(wxBU_BOTTOM) )
{
flags |= DT_BOTTOM;
y0 = pRect->bottom - h;
}
else if ( !btn->HasFlag(wxBU_TOP) )
{
flags |= DT_VCENTER;
// DT_VCENTER
y0 = pRect->top + (pRect->bottom - pRect->top)/2 - h/2;
}
else // DT_TOP is the default
{
y0 = pRect->top;
}
//else: as above, DT_TOP is the default
// notice that we must have DT_SINGLELINE for vertical alignment flags
// to work
::DrawText(hdc, text.t_str(), text.length(), pRect,
flags | DT_SINGLELINE );
UINT dsFlags = DSS_DISABLED;
if( flags & DT_HIDEPREFIX )
dsFlags |= (DSS_HIDEPREFIX | DST_PREFIXTEXT);
else
dsFlags |= DST_TEXT;
const wxArrayString lines = wxSplit(text, '\n', '\0');
const int hLine = h / lines.size();
for ( size_t lineNum = 0; lineNum < lines.size(); lineNum++ )
{
// Each line must be aligned in horizontal direction individually.
::SetRectEmpty(&rc);
::DrawText(hdc, lines[lineNum].t_str(), lines[lineNum].length(),
&rc, DT_CALCRECT);
const LONG w = rc.right - rc.left;
// Based on wxButton flags set horizontal position of the rect
// inside the entire button area. Text is always centered for
// multiline label.
if ( (!btn->HasFlag(wxBU_LEFT) && !btn->HasFlag(wxBU_RIGHT)) ||
lines.size() > 1 )
{
// DT_CENTER
rc.left = pRect->left + (pRect->right - pRect->left)/2 - w/2;
rc.right = rc.left + w;
}
else if ( btn->HasFlag(wxBU_RIGHT) )
{
rc.right = pRect->right;
rc.left = rc.right - w;
}
else // DT_LEFT is the default
{
rc.left = pRect->left;
rc.right = rc.left + w;
}
::OffsetRect(&rc, 0, y0 + lineNum * hLine);
::DrawState(hdc, NULL, NULL, wxMSW_CONV_LPARAM(lines[lineNum]),
lines[lineNum].length(),
rc.left, rc.top, rc.right, rc.bottom, dsFlags);
}
}
else // Button is enabled or using themes.
{
if ( text.find(wxT('\n')) != wxString::npos )
{
// draw multiline label
// center text horizontally in any case
flags |= DT_CENTER;
// first we need to compute its bounding rect
RECT rc;
::CopyRect(&rc, pRect);
::DrawText(hdc, text.t_str(), text.length(), &rc,
DT_CENTER | DT_CALCRECT);
// now center this rect inside the entire button area
const LONG w = rc.right - rc.left;
const LONG h = rc.bottom - rc.top;
rc.left = pRect->left + (pRect->right - pRect->left)/2 - w/2;
rc.right = rc.left+w;
rc.top = pRect->top + (pRect->bottom - pRect->top)/2 - h/2;
rc.bottom = rc.top+h;
::DrawText(hdc, text.t_str(), text.length(), &rc, flags);
}
else // single line label
{
// translate wx button flags to alignment flags for DrawText()
if ( btn->HasFlag(wxBU_RIGHT) )
{
flags |= DT_RIGHT;
}
else if ( !btn->HasFlag(wxBU_LEFT) )
{
flags |= DT_CENTER;
}
//else: DT_LEFT is the default anyhow (and its value is 0 too)
if ( btn->HasFlag(wxBU_BOTTOM) )
{
flags |= DT_BOTTOM;
}
else if ( !btn->HasFlag(wxBU_TOP) )
{
flags |= DT_VCENTER;
}
//else: as above, DT_TOP is the default
// notice that we must have DT_SINGLELINE for vertical alignment
// flags to work
::DrawText(hdc, text.t_str(), text.length(), pRect,
flags | DT_SINGLELINE );
}
}
}