+void DrawRect(HDC hdc, const RECT& r)
+{
+ wxDrawLine(hdc, r.left, r.top, r.right, r.top);
+ wxDrawLine(hdc, r.right, r.top, r.right, r.bottom);
+ wxDrawLine(hdc, r.right, r.bottom, r.left, r.bottom);
+ wxDrawLine(hdc, r.left, r.bottom, r.left, r.top);
+}
+
+/*
+ The button frame looks like this normally:
+
+ WWWWWWWWWWWWWWWWWWB
+ WHHHHHHHHHHHHHHHHGB W = white (HILIGHT)
+ WH GB H = light grey (LIGHT)
+ WH GB G = dark grey (SHADOW)
+ WH GB B = black (DKSHADOW)
+ WH GB
+ WGGGGGGGGGGGGGGGGGB
+ BBBBBBBBBBBBBBBBBBB
+
+ When the button is selected, the button becomes like this (the total button
+ size doesn't change):
+
+ BBBBBBBBBBBBBBBBBBB
+ BWWWWWWWWWWWWWWWWBB
+ BWHHHHHHHHHHHHHHGBB
+ BWH GBB
+ BWH GBB
+ BWGGGGGGGGGGGGGGGBB
+ BBBBBBBBBBBBBBBBBBB
+ BBBBBBBBBBBBBBBBBBB
+
+ When the button is pushed (while selected) it is like:
+
+ BBBBBBBBBBBBBBBBBBB
+ BGGGGGGGGGGGGGGGGGB
+ BG GB
+ BG GB
+ BG GB
+ BG GB
+ BGGGGGGGGGGGGGGGGGB
+ BBBBBBBBBBBBBBBBBBB
+*/
+void DrawButtonFrame(HDC hdc, RECT& rectBtn,
+ bool selected, bool pushed)
+{
+ RECT r;
+ CopyRect(&r, &rectBtn);
+
+ AutoHPEN hpenBlack(GetSysColor(COLOR_3DDKSHADOW)),
+ hpenGrey(GetSysColor(COLOR_3DSHADOW)),
+ hpenLightGr(GetSysColor(COLOR_3DLIGHT)),
+ hpenWhite(GetSysColor(COLOR_3DHILIGHT));
+
+ SelectInHDC selectPen(hdc, hpenBlack);
+
+ r.right--;
+ r.bottom--;
+
+ if ( pushed )
+ {
+ DrawRect(hdc, r);
+
+ (void)SelectObject(hdc, hpenGrey);
+ ::InflateRect(&r, -1, -1);
+
+ DrawRect(hdc, r);
+ }
+ else // !pushed
+ {
+ if ( selected )
+ {
+ DrawRect(hdc, r);
+
+ ::InflateRect(&r, -1, -1);
+ }
+
+ wxDrawLine(hdc, r.left, r.bottom, r.right, r.bottom);
+ wxDrawLine(hdc, r.right, r.bottom, r.right, r.top - 1);
+
+ (void)SelectObject(hdc, hpenWhite);
+ wxDrawLine(hdc, r.left, r.bottom - 1, r.left, r.top);
+ wxDrawLine(hdc, r.left, r.top, r.right, r.top);
+
+ (void)SelectObject(hdc, hpenLightGr);
+ wxDrawLine(hdc, r.left + 1, r.bottom - 2, r.left + 1, r.top + 1);
+ wxDrawLine(hdc, r.left + 1, r.top + 1, r.right - 1, r.top + 1);
+
+ (void)SelectObject(hdc, hpenGrey);
+ wxDrawLine(hdc, r.left + 1, r.bottom - 1, r.right - 1, r.bottom - 1);
+ wxDrawLine(hdc, r.right - 1, r.bottom - 1, r.right - 1, r.top);
+ }
+
+ InflateRect(&rectBtn, -OD_BUTTON_MARGIN, -OD_BUTTON_MARGIN);
+}
+
+#if wxUSE_UXTHEME
+void DrawXPBackground(wxButton *button, HDC hdc, RECT& rectBtn, UINT state)
+{
+ wxUxThemeHandle theme(button, L"BUTTON");
+
+ // this array is indexed by wxButton::State values and so must be kept in
+ // sync with it
+ static const int uxStates[] =
+ {
+ PBS_NORMAL, PBS_HOT, PBS_PRESSED, PBS_DISABLED, PBS_DEFAULTED
+ };
+
+ int iState = uxStates[GetButtonState(button, state)];
+
+ wxUxThemeEngine * const engine = wxUxThemeEngine::Get();
+
+ // draw parent background if needed
+ if ( engine->IsThemeBackgroundPartiallyTransparent
+ (
+ theme,
+ BP_PUSHBUTTON,
+ iState
+ ) )
+ {
+ engine->DrawThemeParentBackground(GetHwndOf(button), hdc, &rectBtn);
+ }
+
+ // draw background
+ engine->DrawThemeBackground(theme, hdc, BP_PUSHBUTTON, iState,
+ &rectBtn, NULL);
+
+ // calculate content area margins
+ MARGINS margins;
+ engine->GetThemeMargins(theme, hdc, BP_PUSHBUTTON, iState,
+ TMT_CONTENTMARGINS, &rectBtn, &margins);
+ ::InflateRect(&rectBtn, -margins.cxLeftWidth, -margins.cyTopHeight);
+ ::InflateRect(&rectBtn, -XP_BUTTON_EXTRA_MARGIN, -XP_BUTTON_EXTRA_MARGIN);
+
+ if ( button->UseBgCol() )
+ {
+ COLORREF colBg = wxColourToRGB(button->GetBackgroundColour());
+ AutoHBRUSH hbrushBackground(colBg);
+
+ // don't overwrite the focus rect
+ RECT rectClient;
+ ::CopyRect(&rectClient, &rectBtn);
+ ::InflateRect(&rectClient, -1, -1);
+ FillRect(hdc, &rectClient, hbrushBackground);
+ }
+}
+#endif // wxUSE_UXTHEME
+
+} // anonymous namespace
+
+// ----------------------------------------------------------------------------
+// owner drawn buttons support
+// ----------------------------------------------------------------------------
+
+void wxButton::MakeOwnerDrawn()
+{
+ long style = GetWindowLong(GetHwnd(), GWL_STYLE);
+ if ( (style & BS_OWNERDRAW) != BS_OWNERDRAW )
+ {
+ // make it so
+ style |= BS_OWNERDRAW;
+ SetWindowLong(GetHwnd(), GWL_STYLE, style);
+ }
+}
+
+bool wxButton::SetBackgroundColour(const wxColour &colour)
+{
+ if ( !wxControl::SetBackgroundColour(colour) )
+ {
+ // nothing to do
+ return false;
+ }
+
+ MakeOwnerDrawn();
+
+ Refresh();
+
+ return true;
+}
+
+bool wxButton::SetForegroundColour(const wxColour &colour)
+{
+ if ( !wxControl::SetForegroundColour(colour) )
+ {
+ // nothing to do
+ return false;
+ }
+
+ MakeOwnerDrawn();
+
+ Refresh();
+
+ return true;
+}
+
+bool wxButton::MSWOnDraw(WXDRAWITEMSTRUCT *wxdis)
+{
+ LPDRAWITEMSTRUCT lpDIS = (LPDRAWITEMSTRUCT)wxdis;
+ HDC hdc = lpDIS->hDC;
+
+ UINT state = lpDIS->itemState;
+ bool pushed = (SendMessage(GetHwnd(), BM_GETSTATE, 0, 0) & BST_PUSHED) != 0;
+
+ RECT rectBtn;
+ CopyRect(&rectBtn, &lpDIS->rcItem);
+
+ // draw the button background
+ if ( !HasFlag(wxBORDER_NONE) )
+ {
+#if wxUSE_UXTHEME
+ if ( wxUxThemeEngine::GetIfActive() )
+ {
+ DrawXPBackground(this, hdc, rectBtn, state);
+ }
+ else
+#endif // wxUSE_UXTHEME
+ {
+ COLORREF colBg = wxColourToRGB(GetBackgroundColour());
+
+ // first, draw the background
+ AutoHBRUSH hbrushBackground(colBg);
+ FillRect(hdc, &rectBtn, hbrushBackground);
+
+ // draw the border for the current state
+ bool selected = (state & ODS_SELECTED) != 0;
+ if ( !selected )
+ {
+ wxTopLevelWindow *
+ tlw = wxDynamicCast(wxGetTopLevelParent(this), wxTopLevelWindow);
+ if ( tlw )
+ {
+ selected = tlw->GetDefaultItem() == this;
+ }
+ }
+
+ DrawButtonFrame(hdc, rectBtn, selected, pushed);
+ }
+
+ // draw the focus rectangle if we need it
+ if ( (state & ODS_FOCUS) && !(state & ODS_NOFOCUSRECT) )
+ {
+ DrawFocusRect(hdc, &rectBtn);
+
+#if wxUSE_UXTHEME
+ if ( !wxUxThemeEngine::GetIfActive() )
+#endif // wxUSE_UXTHEME
+ {
+ if ( pushed )
+ {
+ // the label is shifted by 1 pixel to create "pushed" effect
+ OffsetRect(&rectBtn, 1, 1);
+ }
+ }
+ }
+ }
+
+
+ // draw the image, if any
+ if ( m_imageData )
+ {
+ wxBitmap bmp = m_imageData->GetBitmap(GetButtonState(this, state));
+ if ( !bmp.IsOk() )
+ bmp = m_imageData->GetBitmap(State_Normal);
+
+ const wxSize sizeBmp = bmp.GetSize();
+ const wxSize margin = m_imageData->GetBitmapMargins();
+ const wxSize sizeBmpWithMargins(sizeBmp + 2*margin);
+ wxRect rectButton(wxRectFromRECT(rectBtn));
+
+ // for simplicity, we start with centred rectangle and then move it to
+ // the appropriate edge
+ wxRect rectBitmap = wxRect(sizeBmp).CentreIn(rectButton);
+
+ // move bitmap only if we have a label, otherwise keep it centered
+ if ( ShowsLabel() )
+ {
+ switch ( m_imageData->GetBitmapPosition() )
+ {
+ default:
+ wxFAIL_MSG( "invalid direction" );
+ // fall through
+
+ case wxLEFT:
+ rectBitmap.x = rectButton.x + margin.x;
+ rectButton.x += sizeBmpWithMargins.x;
+ rectButton.width -= sizeBmpWithMargins.x;
+ break;
+
+ case wxRIGHT:
+ rectBitmap.x = rectButton.GetRight() - sizeBmp.x - margin.x;
+ rectButton.width -= sizeBmpWithMargins.x;
+ break;
+
+ case wxTOP:
+ rectBitmap.y = rectButton.y + margin.y;
+ rectButton.y += sizeBmpWithMargins.y;
+ rectButton.height -= sizeBmpWithMargins.y;
+ break;
+
+ case wxBOTTOM:
+ rectBitmap.y = rectButton.GetBottom() - sizeBmp.y - margin.y;
+ rectButton.height -= sizeBmpWithMargins.y;
+ break;
+ }
+ }
+
+ wxDCTemp dst((WXHDC)hdc);
+ dst.DrawBitmap(bmp, rectBitmap.GetPosition(), true);
+
+ wxCopyRectToRECT(rectButton, rectBtn);
+ }
+
+
+ // finally draw the label
+ if ( ShowsLabel() )
+ {
+ COLORREF colFg = state & ODS_DISABLED
+ ? ::GetSysColor(COLOR_GRAYTEXT)
+ : wxColourToRGB(GetForegroundColour());
+
+ // notice that DT_HIDEPREFIX doesn't work on old (pre-Windows 2000)
+ // systems but by happy coincidence ODS_NOACCEL is not used under them
+ // neither so DT_HIDEPREFIX should never be used there
+ DrawButtonText(hdc, &rectBtn, GetLabel(), colFg,
+ state & ODS_NOACCEL ? DT_HIDEPREFIX : 0);
+ }
+
+ return true;
+}
+
+#endif // wxUSE_BUTTON
+