Refactor owner drawn buttons drawing code in wxMSW.

Move it from wxCheckBox to wxControl to allow reusing this code in other
classes, notably wxRadioButton in the upcoming commits.

See #10137.

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@76455 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Vadim Zeitlin 2014-05-04 22:13:07 +00:00
parent 34d3e680c8
commit 3fc6738025
4 changed files with 114 additions and 97 deletions

View File

@ -62,6 +62,8 @@ protected:
virtual void DoSet3StateValue(wxCheckBoxState value);
virtual wxCheckBoxState DoGet3StateValue() const;
virtual void MSWDrawButtonBitmap(wxWindow *win, wxDC& dc,
const wxRect& rect, int flags);
// return true if this checkbox is owner drawn
bool IsOwnerDrawn() const;

View File

@ -124,6 +124,11 @@ protected:
// Look in our GetSubcontrols() for the windows with the given ID.
virtual wxWindow *MSWFindItem(long id, WXHWND hWnd) const;
// For ownerdraw buttons
virtual bool MSWOwnerDrawnButton(const DRAWITEMSTRUCT *dis, int flags, bool isFocused);
virtual void MSWDrawButtonBitmap(wxWindow *WXUNUSED(win), wxDC& WXUNUSED(dc),
const wxRect& WXUNUSED(rect), int WXUNUSED(flags)) {}
// for controls like radiobuttons which are really composite this array
// holds the ids (not HWNDs!) of the sub controls
wxArrayLong m_subControls;

View File

@ -34,7 +34,6 @@
#include "wx/settings.h"
#endif
#include "wx/msw/dc.h" // for wxDCTemp
#include "wx/renderer.h"
#include "wx/msw/uxtheme.h"
#include "wx/msw/private/button.h"
@ -372,46 +371,9 @@ bool wxCheckBox::MSWOnDraw(WXDRAWITEMSTRUCT *item)
if ( !IsOwnerDrawn() || dis->CtlType != ODT_BUTTON )
return wxCheckBoxBase::MSWOnDraw(item);
// calculate the rectangles for the check mark itself and the label
HDC hdc = dis->hDC;
RECT& rect = dis->rcItem;
RECT rectCheck,
rectLabel;
rectLabel.top = rect.top + (rect.bottom - rect.top - GetBestSize().y) / 2;
rectLabel.bottom = rectLabel.top + GetBestSize().y;
const int MARGIN = 3;
const int CXMENUCHECK = ::GetSystemMetrics(SM_CXMENUCHECK);
// the space between the checkbox and the label is included in the
// check-mark bitmap
const int checkSize = wxMin(CXMENUCHECK - MARGIN, GetSize().y);
rectCheck.top = rect.top + (rect.bottom - rect.top - checkSize) / 2;
rectCheck.bottom = rectCheck.top + checkSize;
const bool isRightAligned = HasFlag(wxALIGN_RIGHT);
if ( isRightAligned )
{
rectLabel.right = rect.right - CXMENUCHECK;
rectLabel.left = rect.left;
rectCheck.left = rectLabel.right + ( CXMENUCHECK + MARGIN - checkSize ) / 2;
rectCheck.right = rectCheck.left + checkSize;
}
else // normal, left-aligned checkbox
{
rectCheck.left = rect.left + ( CXMENUCHECK - MARGIN - checkSize ) / 2;
rectCheck.right = rectCheck.left + checkSize;
rectLabel.left = rect.left + CXMENUCHECK;
rectLabel.right = rect.right;
}
// shall we draw a focus rect?
const bool isFocused = m_isPressed || FindFocus() == this;
// draw the checkbox itself
wxDCTemp dc(hdc);
int flags = 0;
if ( !IsEnabled() )
flags |= wxCONTROL_DISABLED;
@ -437,66 +399,12 @@ bool wxCheckBox::MSWOnDraw(WXDRAWITEMSTRUCT *item)
if ( wxFindWindowAtPoint(wxGetMousePosition()) == this )
flags |= wxCONTROL_CURRENT;
wxRendererNative::Get().
DrawCheckBox(this, dc, wxRectFromRECT(rectCheck), flags);
return MSWOwnerDrawnButton(dis, flags, isFocused);
}
// draw the text
const wxString& label = GetLabel();
// first we need to measure it
UINT fmt = DT_NOCLIP;
// drawing underlying doesn't look well with focus rect (and the native
// control doesn't do it)
if ( isFocused )
fmt |= DT_HIDEPREFIX;
if ( isRightAligned )
fmt |= DT_RIGHT;
// TODO: also use DT_HIDEPREFIX if the system is configured so
// we need to get the label real size first if we have to draw a focus rect
// around it
if ( isFocused )
{
RECT oldLabelRect = rectLabel; // needed if right aligned
if ( !::DrawText(hdc, label.t_str(), label.length(), &rectLabel,
fmt | DT_CALCRECT) )
{
wxLogLastError(wxT("DrawText(DT_CALCRECT)"));
}
if ( isRightAligned )
{
// move the label rect to the right
const int labelWidth = rectLabel.right - rectLabel.left;
rectLabel.right = oldLabelRect.right;
rectLabel.left = rectLabel.right - labelWidth;
}
}
if ( !IsEnabled() )
{
::SetTextColor(hdc, ::GetSysColor(COLOR_GRAYTEXT));
}
if ( !::DrawText(hdc, label.t_str(), label.length(), &rectLabel, fmt) )
{
wxLogLastError(wxT("DrawText()"));
}
// finally draw the focus
if ( isFocused )
{
rectLabel.left--;
rectLabel.right++;
if ( !::DrawFocusRect(hdc, &rectLabel) )
{
wxLogLastError(wxT("DrawFocusRect()"));
}
}
return true;
void wxCheckBox::MSWDrawButtonBitmap(wxWindow *win, wxDC& dc, const wxRect& rect, int flags)
{
wxRendererNative::Get().DrawCheckBox(win, dc, rect, flags);
}
#endif // wxUSE_CHECKBOX

View File

@ -47,6 +47,7 @@
#include "wx/msw/private.h"
#include "wx/msw/uxtheme.h"
#include "wx/msw/dc.h" // for wxDCTemp
// ----------------------------------------------------------------------------
// wxWin macros
@ -451,6 +452,107 @@ wxWindow* wxControl::MSWFindItem(long id, WXHWND hWnd) const
return wxControlBase::MSWFindItem(id, hWnd);
}
bool wxControl::MSWOwnerDrawnButton(const DRAWITEMSTRUCT *dis, int flags, bool isFocused)
{
// calculate the rectangles for the button itself and the label
HDC hdc = dis->hDC;
const RECT& rect = dis->rcItem;
// calculate the rectangles for the button itself and the label
RECT rectButton,
rectLabel;
rectLabel.top = rect.top + (rect.bottom - rect.top - GetBestSize().y) / 2;
rectLabel.bottom = rectLabel.top + GetBestSize().y;
const int MARGIN = 3;
const int CXMENUCHECK = ::GetSystemMetrics(SM_CXMENUCHECK);
// The space between the button and the label
// is included in the button bitmap.
const int buttonSize = wxMin(CXMENUCHECK - MARGIN, GetSize().y);
rectButton.top = rect.top + (rect.bottom - rect.top - buttonSize) / 2;
rectButton.bottom = rectButton.top + buttonSize;
const bool isRightAligned = HasFlag(wxALIGN_RIGHT);
if ( isRightAligned )
{
rectLabel.right = rect.right - CXMENUCHECK;
rectLabel.left = rect.left;
rectButton.left = rectLabel.right + ( CXMENUCHECK + MARGIN - buttonSize ) / 2;
rectButton.right = rectButton.left + buttonSize;
}
else // normal, left-aligned button
{
rectButton.left = rect.left + ( CXMENUCHECK - MARGIN - buttonSize ) / 2;
rectButton.right = rectButton.left + buttonSize;
rectLabel.left = rect.left + CXMENUCHECK;
rectLabel.right = rect.right;
}
// draw the button itself
wxDCTemp dc(hdc);
MSWDrawButtonBitmap(this, dc, wxRectFromRECT(rectButton), flags);
// draw the text
const wxString& label = GetLabel();
// first we need to measure it
UINT fmt = DT_NOCLIP;
// drawing underlying doesn't look well with focus rect (and the native
// control doesn't do it)
if ( isFocused )
fmt |= DT_HIDEPREFIX;
if ( isRightAligned )
fmt |= DT_RIGHT;
// TODO: also use DT_HIDEPREFIX if the system is configured so
// we need to get the label real size first if we have to draw a focus rect
// around it
if ( isFocused )
{
RECT oldLabelRect = rectLabel; // needed if right aligned
if ( !::DrawText(hdc, label.t_str(), label.length(), &rectLabel,
fmt | DT_CALCRECT) )
{
wxLogLastError(wxT("DrawText(DT_CALCRECT)"));
}
if ( isRightAligned )
{
// move the label rect to the right
const int labelWidth = rectLabel.right - rectLabel.left;
rectLabel.right = oldLabelRect.right;
rectLabel.left = rectLabel.right - labelWidth;
}
}
if ( !IsEnabled() )
{
::SetTextColor(hdc, ::GetSysColor(COLOR_GRAYTEXT));
}
if ( !::DrawText(hdc, label.t_str(), label.length(), &rectLabel, fmt) )
{
wxLogLastError(wxT("DrawText()"));
}
// finally draw the focus
if ( isFocused )
{
rectLabel.left--;
rectLabel.right++;
if ( !::DrawFocusRect(hdc, &rectLabel) )
{
wxLogLastError(wxT("DrawFocusRect()"));
}
}
return true;
}
// ----------------------------------------------------------------------------
// wxControlWithItems
// ----------------------------------------------------------------------------