From fd743aad4b8bf15e32c34e5c68137f0a7c891631 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Mon, 17 Feb 2014 23:53:25 +0000 Subject: [PATCH] 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 --- src/msw/anybutton.cpp | 155 ++++++++++++++++++++++++++++++++---------- 1 file changed, 118 insertions(+), 37 deletions(-) diff --git a/src/msw/anybutton.cpp b/src/msw/anybutton.cpp index 6a964f059d..d6e367a74e 100644 --- a/src/msw/anybutton.cpp +++ b/src/msw/anybutton.cpp @@ -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 ); + } } }