From: Vadim Zeitlin Date: Mon, 15 Jun 2009 23:10:16 +0000 (+0000) Subject: implement wxBitmapButton as just a wrapper for wxButton under MSW X-Git-Url: https://git.saurik.com/wxWidgets.git/commitdiff_plain/a6fd73d33ac80632981dee1c0be669f20ba765b5 implement wxBitmapButton as just a wrapper for wxButton under MSW git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@61071 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- diff --git a/include/wx/bmpbuttn.h b/include/wx/bmpbuttn.h index 0c369003e0..d9a1b3a727 100644 --- a/include/wx/bmpbuttn.h +++ b/include/wx/bmpbuttn.h @@ -16,10 +16,14 @@ #if wxUSE_BMPBUTTON -#include "wx/bitmap.h" #include "wx/button.h" -extern WXDLLIMPEXP_DATA_CORE(const char) wxButtonNameStr[]; +// FIXME: right now only wxMSW implements bitmap support in wxButton +// itself, this shouldn't be used for the other platforms neither +// when all of them do it +#ifdef __WXMSW__ + #define wxHAS_BUTTON_BITMAP +#endif // ---------------------------------------------------------------------------- // wxBitmapButton: a button which shows bitmaps instead of the usual string. @@ -31,18 +35,25 @@ class WXDLLIMPEXP_CORE wxBitmapButtonBase : public wxButton public: wxBitmapButtonBase() { +#ifndef wxHAS_BUTTON_BITMAP m_marginX = m_marginY = 0; +#endif // wxHAS_BUTTON_BITMAP } // set/get the margins around the button - virtual void SetMargins(int x, int y) { m_marginX = x; m_marginY = y; } - int GetMarginX() const { return m_marginX; } - int GetMarginY() const { return m_marginY; } + virtual void SetMargins(int x, int y) + { + DoSetBitmapMargins(x, y); + } + + int GetMarginX() const { return DoGetBitmapMargins().x; } + int GetMarginY() const { return DoGetBitmapMargins().y; } // deprecated synonym for SetBitmapLabel() #if WXWIN_COMPATIBILITY_2_6 - wxDEPRECATED( void SetLabel(const wxBitmap& bitmap) ); + wxDEPRECATED_INLINE( void SetLabel(const wxBitmap& bitmap). + SetBitmapLabel(bitmap); ); // prevent virtual function hiding virtual void SetLabel(const wxString& label) @@ -50,6 +61,7 @@ public: #endif // WXWIN_COMPATIBILITY_2_6 protected: +#ifndef wxHAS_BUTTON_BITMAP // function called when any of the bitmaps changes virtual void OnSetBitmap() { InvalidateBestSize(); Refresh(); } @@ -57,24 +69,28 @@ protected: virtual void DoSetBitmap(const wxBitmap& bitmap, State which) { m_bitmaps[which] = bitmap; OnSetBitmap(); } + virtual wxSize DoGetBitmapMargins() const + { + return wxSize(m_marginX, m_marginY); + } + + virtual void DoSetBitmapMargins(int x, int y) + { + m_marginX = x; + m_marginY = y; + } + // the bitmaps for various states wxBitmap m_bitmaps[State_Max]; // the margins around the bitmap int m_marginX, m_marginY; - +#endif // !wxHAS_BUTTON_BITMAP wxDECLARE_NO_COPY_CLASS(wxBitmapButtonBase); }; -#if WXWIN_COMPATIBILITY_2_6 -inline void wxBitmapButtonBase::SetLabel(const wxBitmap& bitmap) -{ - SetBitmapLabel(bitmap); -} -#endif // WXWIN_COMPATIBILITY_2_6 - #if defined(__WXUNIVERSAL__) #include "wx/univ/bmpbuttn.h" #elif defined(__WXMSW__) diff --git a/include/wx/button.h b/include/wx/button.h index e2d3dbcd85..53b164bbba 100644 --- a/include/wx/button.h +++ b/include/wx/button.h @@ -155,8 +155,13 @@ protected: virtual void DoSetBitmap(const wxBitmap& WXUNUSED(bitmap), State WXUNUSED(which)) { } + + virtual wxSize DoGetBitmapMargins() const + { return wxSize(0, 0); } + virtual void DoSetBitmapMargins(wxCoord WXUNUSED(x), wxCoord WXUNUSED(y)) { } + virtual void DoSetBitmapPosition(wxDirection WXUNUSED(dir)) { } diff --git a/include/wx/msw/bmpbuttn.h b/include/wx/msw/bmpbuttn.h index a0d1dfd2fe..aff0c0fe14 100644 --- a/include/wx/msw/bmpbuttn.h +++ b/include/wx/msw/bmpbuttn.h @@ -44,13 +44,6 @@ public: const wxValidator& validator = wxDefaultValidator, const wxString& name = wxButtonNameStr); - // Implementation - virtual bool SetBackgroundColour(const wxColour& colour); - virtual bool MSWOnDraw(WXDRAWITEMSTRUCT *item); - virtual void DrawFace( WXHDC dc, int left, int top, int right, int bottom, bool sel ); - virtual void DrawButtonFocus( WXHDC dc, int left, int top, int right, int bottom, bool sel ); - virtual void DrawButtonDisable( WXHDC dc, int left, int top, int right, int bottom, bool with_marg ); - protected: // common part of all ctors void Init() @@ -60,22 +53,8 @@ protected: } // reimplement some base class virtuals - virtual wxSize DoGetBestSize() const; - virtual WXDWORD MSWGetStyle(long style, WXDWORD *exstyle) const; - virtual void DoSetBitmap(const wxBitmap& bitmap, State which); - - // invalidate m_brushDisabled when system colours change - void OnSysColourChanged(wxSysColourChangedEvent& event); - - // change the currently bitmap if we have a hover one - void OnMouseEnterOrLeave(wxMouseEvent& event); - - - // the brush we use to draw disabled buttons - wxBrush m_brushDisabled; - // true if disabled bitmap was set by user, false if we created it // ourselves from the normal one bool m_disabledSetByUser; diff --git a/include/wx/msw/button.h b/include/wx/msw/button.h index 19d204f2e1..52ca818cbe 100644 --- a/include/wx/msw/button.h +++ b/include/wx/msw/button.h @@ -82,6 +82,7 @@ protected: virtual wxBitmap DoGetBitmap(State which) const; virtual void DoSetBitmap(const wxBitmap& bitmap, State which); + virtual wxSize DoGetBitmapMargins() const; virtual void DoSetBitmapMargins(wxCoord x, wxCoord y); virtual void DoSetBitmapPosition(wxDirection dir); diff --git a/src/msw/bmpbuttn.cpp b/src/msw/bmpbuttn.cpp index 0f38686c31..1438b7cffa 100644 --- a/src/msw/bmpbuttn.cpp +++ b/src/msw/bmpbuttn.cpp @@ -110,8 +110,6 @@ IMPLEMENT_DYNAMIC_CLASS(wxBitmapButton, wxButton) BEGIN_EVENT_TABLE(wxBitmapButton, wxBitmapButtonBase) EVT_SYS_COLOUR_CHANGED(wxBitmapButton::OnSysColourChanged) - EVT_ENTER_WINDOW(wxBitmapButton::OnMouseEnterOrLeave) - EVT_LEAVE_WINDOW(wxBitmapButton::OnMouseEnterOrLeave) END_EVENT_TABLE() /* @@ -132,70 +130,15 @@ bool wxBitmapButton::Create(wxWindow *parent, const wxValidator& wxVALIDATOR_PARAM(validator), const wxString& name) { - if ( !CreateControl(parent, id, pos, size, style, validator, name) ) + if ( !wxBitmapButtonBase::Create(parent, id, "", + pos, size, style, validator, name) ) return false; SetBitmapLabel(bitmap); - if ( style & wxBU_AUTODRAW ) - SetMargins(4, 4); - - return MSWCreateControl(_T("BUTTON"), wxEmptyString, pos, size); -} - -WXDWORD wxBitmapButton::MSWGetStyle(long style, WXDWORD *exstyle) const -{ - WXDWORD msStyle = wxButton::MSWGetStyle(style, exstyle); - - msStyle |= BS_OWNERDRAW; - - if ( style & wxBU_LEFT ) - msStyle |= BS_LEFT; - if ( style & wxBU_RIGHT ) - msStyle |= BS_RIGHT; - if ( style & wxBU_TOP ) - msStyle |= BS_TOP; - if ( style & wxBU_BOTTOM ) - msStyle |= BS_BOTTOM; - - return msStyle; -} - -bool wxBitmapButton::SetBackgroundColour(const wxColour& colour) -{ - if ( !wxBitmapButtonBase::SetBackgroundColour(colour) ) - { - // didn't change - return false; - } - - // invalidate the brush, it will be recreated the next time it's needed - m_brushDisabled = wxNullBrush; - return true; } -void wxBitmapButton::OnSysColourChanged(wxSysColourChangedEvent& event) -{ - m_brushDisabled = wxNullBrush; - - if ( !IsEnabled() ) - { - // this change affects our current state - Refresh(); - } - - event.Skip(); -} - -void wxBitmapButton::OnMouseEnterOrLeave(wxMouseEvent& event) -{ - if ( IsEnabled() && m_bitmaps[State_Current].IsOk() ) - Refresh(); - - event.Skip(); -} - void wxBitmapButton::DoSetBitmap(const wxBitmap& bitmap, State which) { if ( bitmap.IsOk() ) @@ -207,7 +150,7 @@ void wxBitmapButton::DoSetBitmap(const wxBitmap& bitmap, State which) if ( !HasFlag(wxBU_AUTODRAW) && !m_disabledSetByUser ) { wxImage img(bitmap.ConvertToImage().ConvertToGreyscale()); - m_bitmaps[State_Disabled] = wxBitmap(img); + wxBitmapButtonBase::DoSetBitmap(img, State_Disabled); } break; #endif // wxUSE_IMAGE @@ -222,7 +165,7 @@ void wxBitmapButton::DoSetBitmap(const wxBitmap& bitmap, State which) // all platforms (some of them, such as Windows XP, have "hot" // buttons while others don't) if ( !m_hoverSetByUser ) - m_bitmaps[State_Current] = bitmap; + wxBitmapButtonBase::DoSetBitmap(bitmap, State_Current); break; case State_Current: @@ -241,403 +184,4 @@ void wxBitmapButton::DoSetBitmap(const wxBitmap& bitmap, State which) wxBitmapButtonBase::DoSetBitmap(bitmap, which); } -#if wxUSE_UXTHEME -static -void MSWDrawXPBackground(wxButton *button, WXDRAWITEMSTRUCT *wxdis) -{ - LPDRAWITEMSTRUCT lpDIS = (LPDRAWITEMSTRUCT)wxdis; - HDC hdc = lpDIS->hDC; - UINT state = lpDIS->itemState; - RECT rectBtn; - CopyRect(&rectBtn, &lpDIS->rcItem); - - wxUxThemeHandle theme(button, L"BUTTON"); - int iState; - - if ( state & ODS_SELECTED ) - { - iState = PBS_PRESSED; - } - else if ( button->HasCapture() || button->IsMouseInWindow() ) - { - iState = PBS_HOT; - } - else if ( state & ODS_FOCUS ) - { - iState = PBS_DEFAULTED; - } - else if ( state & ODS_DISABLED ) - { - iState = PBS_DISABLED; - } - else - { - iState = PBS_NORMAL; - } - - // draw parent background if needed - if ( wxUxThemeEngine::Get()->IsThemeBackgroundPartiallyTransparent(theme, - BP_PUSHBUTTON, - iState) ) - { - wxUxThemeEngine::Get()->DrawThemeParentBackground(GetHwndOf(button), hdc, &rectBtn); - } - - // draw background - wxUxThemeEngine::Get()->DrawThemeBackground(theme, hdc, BP_PUSHBUTTON, iState, - &rectBtn, NULL); - - // calculate content area margins - MARGINS margins; - wxUxThemeEngine::Get()->GetThemeMargins(theme, hdc, BP_PUSHBUTTON, iState, - TMT_CONTENTMARGINS, &rectBtn, &margins); - RECT rectClient; - ::CopyRect(&rectClient, &rectBtn); - ::InflateRect(&rectClient, -margins.cxLeftWidth, -margins.cyTopHeight); - - // if focused and !nofocus rect - if ( (state & ODS_FOCUS) && !(state & ODS_NOFOCUSRECT) ) - { - DrawFocusRect(hdc, &rectClient); - } - - if ( button->UseBgCol() ) - { - COLORREF colBg = wxColourToRGB(button->GetBackgroundColour()); - HBRUSH hbrushBackground = ::CreateSolidBrush(colBg); - - // don't overwrite the focus rect - ::InflateRect(&rectClient, -1, -1); - FillRect(hdc, &rectClient, hbrushBackground); - ::DeleteObject(hbrushBackground); - } -} -#endif // wxUSE_UXTHEME - -// VZ: should be at the very least less than wxDEFAULT_BUTTON_MARGIN -#define FOCUS_MARGIN 3 - -bool wxBitmapButton::MSWOnDraw(WXDRAWITEMSTRUCT *item) -{ -#ifndef __WXWINCE__ - long style = GetWindowLong((HWND) GetHWND(), GWL_STYLE); - if (style & BS_BITMAP) - { - // Let default procedure draw the bitmap, which is defined - // in the Windows resource. - return false; - } -#endif - - LPDRAWITEMSTRUCT lpDIS = (LPDRAWITEMSTRUCT) item; - HDC hDC = lpDIS->hDC; - UINT state = lpDIS->itemState; - bool isSelected = (state & ODS_SELECTED) != 0; - bool autoDraw = HasFlag(wxBU_AUTODRAW); - - - // choose the bitmap to use depending on the button state - wxBitmap bitmap; - - if ( isSelected ) - bitmap = GetBitmapSelected(); - else if ( IsMouseInWindow() ) - bitmap = GetBitmapCurrent(); - else if ( state & ODS_DISABLED ) - bitmap = GetBitmapDisabled(); - - if ( !bitmap.IsOk() ) - { - if ( state & ODS_FOCUS ) - bitmap = GetBitmapFocus(); - - if ( !bitmap.IsOk() ) - bitmap = GetBitmapLabel(); - - if ( !bitmap.IsOk() ) - return false; - } - - // centre the bitmap in the control area - int x = lpDIS->rcItem.left; - int y = lpDIS->rcItem.top; - int width = lpDIS->rcItem.right - x; - int height = lpDIS->rcItem.bottom - y; - int wBmp = bitmap.GetWidth(); - int hBmp = bitmap.GetHeight(); - -#if wxUSE_UXTHEME - if ( autoDraw && wxUxThemeEngine::GetIfActive() ) - { - MSWDrawXPBackground(this, item); - wxUxThemeHandle theme(this, L"BUTTON"); - - // calculate content area margins - // assuming here that each state is the same size - MARGINS margins; - wxUxThemeEngine::Get()->GetThemeMargins(theme, NULL, - BP_PUSHBUTTON, PBS_NORMAL, - TMT_CONTENTMARGINS, NULL, - &margins); - int marginX = margins.cxLeftWidth + 1; - int marginY = margins.cyTopHeight + 1; - int x1,y1; - - if ( m_windowStyle & wxBU_LEFT ) - { - x1 = x + marginX; - } - else if ( m_windowStyle & wxBU_RIGHT ) - { - x1 = x + (width - wBmp) - marginX; - } - else - { - x1 = x + (width - wBmp) / 2; - } - - if ( m_windowStyle & wxBU_TOP ) - { - y1 = y + marginY; - } - else if ( m_windowStyle & wxBU_BOTTOM ) - { - y1 = y + (height - hBmp) - marginY; - } - else - { - y1 = y + (height - hBmp) / 2; - } - - // draw the bitmap - wxDCTemp dst((WXHDC)hDC); - dst.DrawBitmap(bitmap, x1, y1, true); - - return true; - } -#endif // wxUSE_UXTHEME - - int x1,y1; - - if(m_windowStyle & wxBU_LEFT) - x1 = x + (FOCUS_MARGIN+1); - else if(m_windowStyle & wxBU_RIGHT) - x1 = x + (width - wBmp) - (FOCUS_MARGIN+1); - else - x1 = x + (width - wBmp) / 2; - - if(m_windowStyle & wxBU_TOP) - y1 = y + (FOCUS_MARGIN+1); - else if(m_windowStyle & wxBU_BOTTOM) - y1 = y + (height - hBmp) - (FOCUS_MARGIN+1); - else - y1 = y + (height - hBmp) / 2; - - if ( isSelected && autoDraw ) - { - x1++; - y1++; - } - - // draw the face, if auto-drawing - if ( autoDraw ) - { - DrawFace((WXHDC) hDC, - lpDIS->rcItem.left, lpDIS->rcItem.top, - lpDIS->rcItem.right, lpDIS->rcItem.bottom, - isSelected); - } - - // draw the bitmap - wxDCTemp dst((WXHDC)hDC); - dst.DrawBitmap(bitmap, x1, y1, true); - - // draw focus / disabled state, if auto-drawing - if ( (state & ODS_DISABLED) && autoDraw ) - { - DrawButtonDisable((WXHDC) hDC, - lpDIS->rcItem.left, lpDIS->rcItem.top, - lpDIS->rcItem.right, lpDIS->rcItem.bottom, - true); - } - else if ( (state & ODS_FOCUS) && autoDraw ) - { - DrawButtonFocus((WXHDC) hDC, - lpDIS->rcItem.left, - lpDIS->rcItem.top, - lpDIS->rcItem.right, - lpDIS->rcItem.bottom, - isSelected); - } - - return true; -} - -// GRG Feb/2000, support for bmp buttons with Win95/98 standard LNF - -void wxBitmapButton::DrawFace( WXHDC dc, int left, int top, - int right, int bottom, bool sel ) -{ - HPEN oldp; - HPEN penHiLight; - HPEN penLight; - HPEN penShadow; - HPEN penDkShadow; - HBRUSH brushFace; - - // create needed pens and brush - penHiLight = CreatePen(PS_SOLID, 0, GetSysColor(COLOR_3DHILIGHT)); - penLight = CreatePen(PS_SOLID, 0, GetSysColor(COLOR_3DLIGHT)); - penShadow = CreatePen(PS_SOLID, 0, GetSysColor(COLOR_3DSHADOW)); - penDkShadow = CreatePen(PS_SOLID, 0, GetSysColor(COLOR_3DDKSHADOW)); - brushFace = CreateSolidBrush(GetSysColor(COLOR_BTNFACE)); - - // draw the rectangle - RECT rect; - rect.left = left; - rect.right = right; - rect.top = top; - rect.bottom = bottom; - FillRect((HDC) dc, &rect, brushFace); - - // draw the border - oldp = (HPEN) SelectObject( (HDC) dc, sel? penDkShadow : penHiLight); - - wxDrawLine((HDC) dc, left, top, right-1, top); - wxDrawLine((HDC) dc, left, top+1, left, bottom-1); - - SelectObject( (HDC) dc, sel? penShadow : penLight); - wxDrawLine((HDC) dc, left+1, top+1, right-2, top+1); - wxDrawLine((HDC) dc, left+1, top+2, left+1, bottom-2); - - SelectObject( (HDC) dc, sel? penLight : penShadow); - wxDrawLine((HDC) dc, left+1, bottom-2, right-1, bottom-2); - wxDrawLine((HDC) dc, right-2, bottom-3, right-2, top); - - SelectObject( (HDC) dc, sel? penHiLight : penDkShadow); - wxDrawLine((HDC) dc, left, bottom-1, right+2, bottom-1); - wxDrawLine((HDC) dc, right-1, bottom-2, right-1, top-1); - - // delete allocated resources - SelectObject((HDC) dc,oldp); - DeleteObject(penHiLight); - DeleteObject(penLight); - DeleteObject(penShadow); - DeleteObject(penDkShadow); - DeleteObject(brushFace); -} - -void wxBitmapButton::DrawButtonFocus( WXHDC dc, int left, int top, int right, - int bottom, bool WXUNUSED(sel) ) -{ - RECT rect; - rect.left = left; - rect.top = top; - rect.right = right; - rect.bottom = bottom; - InflateRect( &rect, - FOCUS_MARGIN, - FOCUS_MARGIN ); - - // GRG: the focus rectangle should not move when the button is pushed! -/* - if ( sel ) - OffsetRect( &rect, 1, 1 ); -*/ - - DrawFocusRect( (HDC) dc, &rect ); -} - -void -wxBitmapButton::DrawButtonDisable( WXHDC dc, - int left, int top, int right, int bottom, - bool with_marg ) -{ - if ( !m_brushDisabled.IsOk() ) - { - // draw a bitmap with two black and two background colour pixels - wxBitmap bmp(2, 2); - wxMemoryDC dc; - dc.SelectObject(bmp); - dc.SetPen(*wxBLACK_PEN); - dc.DrawPoint(0, 0); - dc.DrawPoint(1, 1); - dc.SetPen(GetBackgroundColour()); - dc.DrawPoint(0, 1); - dc.DrawPoint(1, 0); - - m_brushDisabled = wxBrush(bmp); - } - - SelectInHDC selectBrush((HDC)dc, GetHbrushOf(m_brushDisabled)); - - // ROP for "dest |= pattern" operation -- as it doesn't have a standard - // name, give it our own - static const DWORD PATTERNPAINT = 0xFA0089UL; - - if ( with_marg ) - { - left += m_marginX; - top += m_marginY; - right -= 2 * m_marginX; - bottom -= 2 * m_marginY; - } - - ::PatBlt( (HDC) dc, left, top, right, bottom, PATTERNPAINT); -} - -wxSize wxBitmapButton::DoGetBestSize() const -{ - if ( GetBitmapLabel().IsOk() ) - { - int width = GetBitmapLabel().GetWidth(), - height = GetBitmapLabel().GetHeight(); - int marginH = 0, - marginV = 0; - -#if wxUSE_UXTHEME - if ( wxUxThemeEngine::GetIfActive() ) - { - wxUxThemeHandle theme((wxBitmapButton *)this, L"BUTTON"); - - MARGINS margins; - wxUxThemeEngine::Get()->GetThemeMargins(theme, NULL, - BP_PUSHBUTTON, PBS_NORMAL, - TMT_CONTENTMARGINS, NULL, - &margins); - - // XP doesn't draw themed buttons correctly when the client area is - // smaller than 8x8 - enforce this minimum size for small bitmaps - if ( width < 8 ) - width = 8; - if ( height < 8 ) - height = 8; - - // don't add margins for the borderless buttons, they don't need - // them and it just makes them appear larger than needed - if ( !HasFlag(wxBORDER_NONE) ) - { - // we need 2 extra pixels for the focus rectangle, without them - // it's overwritten by the bitmap itself - marginH = margins.cxLeftWidth + margins.cxRightWidth + 2; - marginV = margins.cyTopHeight + margins.cyBottomHeight + 2; - } - } - else -#endif // wxUSE_UXTHEME - { - if ( !HasFlag(wxBORDER_NONE) ) - { - marginH = 2*m_marginX; - marginV = 2*m_marginY; - } - } - - wxSize best(width + marginH, height + marginV); - CacheBestSize(best); - return best; - } - - // no idea what our best size should be, defer to the base class - return wxBitmapButtonBase::DoGetBestSize(); -} - #endif // wxUSE_BMPBUTTON diff --git a/src/msw/button.cpp b/src/msw/button.cpp index b88fec20b0..b789a6ccc2 100644 --- a/src/msw/button.cpp +++ b/src/msw/button.cpp @@ -143,8 +143,13 @@ public: m_dir = wxLEFT; - m_margin.x = btn->GetCharWidth(); - m_margin.y = btn->GetCharHeight() / 2; + // we use margins when we have both bitmap and text, but when we have + // only the bitmap it should take up the entire button area + if ( !btn->GetLabel().empty() ) + { + m_margin.x = btn->GetCharWidth(); + m_margin.y = btn->GetCharHeight() / 2; + } } virtual wxBitmap GetBitmap(wxButton::State which) const @@ -159,7 +164,7 @@ public: virtual wxSize GetBitmapMargins() const { - return m_margin + wxSize(OD_BUTTON_MARGIN, OD_BUTTON_MARGIN); + return m_margin; } virtual void SetBitmapMargins(wxCoord x, wxCoord y) @@ -189,6 +194,10 @@ private: #if wxUSE_UXTHEME +// somehow the margin is one pixel greater than the value returned by +// GetThemeMargins() call +const int XP_BUTTON_EXTRA_MARGIN = 1; + class wxXPButtonImageData : public wxButtonImageData { public: @@ -215,6 +224,8 @@ public: // and default alignment m_data.uAlign = BUTTON_IMAGELIST_ALIGN_LEFT; + + UpdateImageInfo(); } virtual wxBitmap GetBitmap(wxButton::State which) const @@ -561,9 +572,17 @@ void wxButton::SetLabel(const wxString& label) wxSize wxButton::DoGetBestSize() const { - wxSize size = wxMSWButton::ComputeBestSize(const_cast(this)); + wxSize size; + + // account for the text part + if ( !GetLabel().empty() ) + { + size = wxMSWButton::ComputeBestSize(const_cast(this)); + } + if ( m_imageData ) { + // account for the bitmap size const wxSize sizeBmp = m_imageData->GetBitmap(State_Normal).GetSize(); const wxDirection dirBmp = m_imageData->GetBitmapPosition(); if ( dirBmp == wxLEFT || dirBmp == wxRIGHT ) @@ -579,8 +598,46 @@ wxSize wxButton::DoGetBestSize() const size.x = sizeBmp.x; } + // account for the user-specified margins size += 2*m_imageData->GetBitmapMargins(); + // and also for the margins we always add internally + int marginH = 0, + marginV = 0; +#if wxUSE_UXTHEME + if ( wxUxThemeEngine::GetIfActive() ) + { + wxUxThemeHandle theme(const_cast(this), L"BUTTON"); + + MARGINS margins; + wxUxThemeEngine::Get()->GetThemeMargins(theme, NULL, + BP_PUSHBUTTON, PBS_NORMAL, + TMT_CONTENTMARGINS, NULL, + &margins); + + // XP doesn't draw themed buttons correctly when the client area is + // smaller than 8x8 - enforce this minimum size for small bitmaps + size.IncTo(wxSize(8, 8)); + + // don't add margins for the borderless buttons, they don't need + // them and it just makes them appear larger than needed + if ( !HasFlag(wxBORDER_NONE) ) + { + marginH = margins.cxLeftWidth + margins.cxRightWidth + + 2*XP_BUTTON_EXTRA_MARGIN; + marginV = margins.cyTopHeight + margins.cyBottomHeight + + 2*XP_BUTTON_EXTRA_MARGIN; + } + } + else +#endif // wxUSE_UXTHEME + { + marginH = + marginV = OD_BUTTON_MARGIN; + } + + size.IncBy(marginH, marginV); + CacheBestSize(size); } @@ -853,10 +910,13 @@ WXLRESULT wxButton::MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam) nMsg == WM_MOUSELEAVE ) { if ( + IsEnabled() && + ( #if wxUSE_UXTHEME wxUxThemeEngine::GetIfActive() || #endif // wxUSE_UXTHEME m_imageData && m_imageData->GetBitmap(State_Current).IsOk() + ) ) { Refresh(); @@ -882,7 +942,11 @@ void wxButton::DoSetBitmap(const wxBitmap& bitmap, State which) if ( !m_imageData ) { #if wxUSE_UXTHEME - if ( wxUxThemeEngine::GetIfActive() ) + // using image list doesn't work correctly if we don't have any label + // (even if we use BUTTON_IMAGELIST_ALIGN_CENTER alignment and + // BS_BITMAP style), at least under Windows 2003 so use owner drawn + // strategy for bitmap-only buttons + if ( !GetLabel().empty() && wxUxThemeEngine::GetIfActive() ) { m_imageData = new wxXPButtonImageData(this, bitmap); } @@ -901,6 +965,13 @@ void wxButton::DoSetBitmap(const wxBitmap& bitmap, State which) { m_imageData->SetBitmap(bitmap, which); } + + Refresh(); +} + +wxSize wxButton::DoGetBitmapMargins() const +{ + return m_imageData ? m_imageData->GetBitmapMargins() : wxSize(0, 0); } void wxButton::DoSetBitmapMargins(wxCoord x, wxCoord y) @@ -1117,6 +1188,7 @@ void DrawXPBackground(wxButton *button, HDC hdc, RECT& rectBtn, UINT state) 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() ) { @@ -1190,6 +1262,8 @@ bool wxButton::MSWOnDraw(WXDRAWITEMSTRUCT *wxdis) RECT rectBtn; CopyRect(&rectBtn, &lpDIS->rcItem); + const wxString label = GetLabel(); + // draw the button background #if wxUSE_UXTHEME if ( wxUxThemeEngine::GetIfActive() ) @@ -1290,15 +1364,18 @@ bool wxButton::MSWOnDraw(WXDRAWITEMSTRUCT *wxdis) // finally draw the label - 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); + if ( !label.empty() ) + { + 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, label, colFg, + state & ODS_NOACCEL ? DT_HIDEPREFIX : 0); + } return true; }