X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/8f4745feeb2850f3bebb3af45407e164550d541a..06f28e557258a48f6a4b7ccb6aa08448c025ab68:/src/msw/button.cpp diff --git a/src/msw/button.cpp b/src/msw/button.cpp index 2b0243b249..240e2e9813 100644 --- a/src/msw/button.cpp +++ b/src/msw/button.cpp @@ -37,13 +37,16 @@ #include "wx/dcscreen.h" #include "wx/dcclient.h" #include "wx/toplevel.h" - #include "wx/imaglist.h" + #include "wx/msw/wrapcctl.h" + #include "wx/msw/private.h" + #include "wx/msw/missing.h" #endif +#include "wx/imaglist.h" #include "wx/stockitem.h" -#include "wx/msw/private.h" #include "wx/msw/private/button.h" #include "wx/msw/private/dc.h" +#include "wx/private/window.h" using namespace wxMSWImpl; @@ -102,6 +105,12 @@ using namespace wxMSWImpl; #define DT_HIDEPREFIX 0x00100000 #endif +// set the value for BCM_SETSHIELD (for the UAC shield) if it's not defined in +// the header +#ifndef BCM_SETSHIELD + #define BCM_SETSHIELD 0x160c +#endif + // ---------------------------------------------------------------------------- // button image data // ---------------------------------------------------------------------------- @@ -137,12 +146,19 @@ const int OD_BUTTON_MARGIN = 4; class wxODButtonImageData : public wxButtonImageData { public: - wxODButtonImageData(wxButton *btn) + wxODButtonImageData(wxButton *btn, const wxBitmap& bitmap) { + SetBitmap(bitmap, wxButton::State_Normal); + 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->ShowsLabel() ) + { + m_margin.x = btn->GetCharWidth(); + m_margin.y = btn->GetCharHeight() / 2; + } } virtual wxBitmap GetBitmap(wxButton::State which) const @@ -157,7 +173,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) @@ -187,15 +203,26 @@ 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: // we must be constructed with the size of our images as we need to create // the image list - wxXPButtonImageData(wxButton *btn, const wxSize& size) - : m_iml(size.x, size.y, true /* use mask */, wxButton::State_Max), + wxXPButtonImageData(wxButton *btn, const wxBitmap& bitmap) + : m_iml(bitmap.GetWidth(), bitmap.GetHeight(), true /* use mask */, + wxButton::State_Max), m_hwndBtn(GetHwndOf(btn)) { + // initialize all bitmaps to normal state + for ( int n = 0; n < wxButton::State_Max; n++ ) + { + m_iml.Add(bitmap); + } + m_data.himl = GetHimagelistOf(&m_iml); // use default margins @@ -206,6 +233,8 @@ public: // and default alignment m_data.uAlign = BUTTON_IMAGELIST_ALIGN_LEFT; + + UpdateImageInfo(); } virtual wxBitmap GetBitmap(wxButton::State which) const @@ -215,22 +244,7 @@ public: virtual void SetBitmap(const wxBitmap& bitmap, wxButton::State which) { - const int imagesToAdd = which - m_iml.GetImageCount(); - if ( imagesToAdd >= 0 ) - { - if ( imagesToAdd > 0 ) - { - const wxBitmap bmpNormal = GetBitmap(wxButton::State_Normal); - for ( int n = 0; n < imagesToAdd; n++ ) - m_iml.Add(bmpNormal); - } - - m_iml.Add(bitmap); - } - else // we already have this bitmap - { - m_iml.Replace(which, bitmap); - } + m_iml.Replace(which, bitmap); UpdateImageInfo(); } @@ -340,67 +354,6 @@ private: // macros // ---------------------------------------------------------------------------- -#if wxUSE_EXTENDED_RTTI - -WX_DEFINE_FLAGS( wxButtonStyle ) - -wxBEGIN_FLAGS( wxButtonStyle ) - // new style border flags, we put them first to - // use them for streaming out - wxFLAGS_MEMBER(wxBORDER_SIMPLE) - wxFLAGS_MEMBER(wxBORDER_SUNKEN) - wxFLAGS_MEMBER(wxBORDER_DOUBLE) - wxFLAGS_MEMBER(wxBORDER_RAISED) - wxFLAGS_MEMBER(wxBORDER_STATIC) - wxFLAGS_MEMBER(wxBORDER_NONE) - - // old style border flags - wxFLAGS_MEMBER(wxSIMPLE_BORDER) - wxFLAGS_MEMBER(wxSUNKEN_BORDER) - wxFLAGS_MEMBER(wxDOUBLE_BORDER) - wxFLAGS_MEMBER(wxRAISED_BORDER) - wxFLAGS_MEMBER(wxSTATIC_BORDER) - wxFLAGS_MEMBER(wxBORDER) - - // standard window styles - wxFLAGS_MEMBER(wxTAB_TRAVERSAL) - wxFLAGS_MEMBER(wxCLIP_CHILDREN) - wxFLAGS_MEMBER(wxTRANSPARENT_WINDOW) - wxFLAGS_MEMBER(wxWANTS_CHARS) - wxFLAGS_MEMBER(wxFULL_REPAINT_ON_RESIZE) - wxFLAGS_MEMBER(wxALWAYS_SHOW_SB ) - wxFLAGS_MEMBER(wxVSCROLL) - wxFLAGS_MEMBER(wxHSCROLL) - - wxFLAGS_MEMBER(wxBU_LEFT) - wxFLAGS_MEMBER(wxBU_RIGHT) - wxFLAGS_MEMBER(wxBU_TOP) - wxFLAGS_MEMBER(wxBU_BOTTOM) - wxFLAGS_MEMBER(wxBU_EXACTFIT) -wxEND_FLAGS( wxButtonStyle ) - -IMPLEMENT_DYNAMIC_CLASS_XTI(wxButton, wxControl,"wx/button.h") - -wxBEGIN_PROPERTIES_TABLE(wxButton) - wxEVENT_PROPERTY( Click , wxEVT_COMMAND_BUTTON_CLICKED , wxCommandEvent) - - wxPROPERTY( Font , wxFont , SetFont , GetFont , EMPTY_MACROVALUE, 0 /*flags*/ , wxT("Helpstring") , wxT("group")) - wxPROPERTY( Label, wxString , SetLabel, GetLabel, wxString(), 0 /*flags*/ , wxT("Helpstring") , wxT("group") ) - - wxPROPERTY_FLAGS( WindowStyle , wxButtonStyle , long , SetWindowStyleFlag , GetWindowStyleFlag , EMPTY_MACROVALUE , 0 /*flags*/ , wxT("Helpstring") , wxT("group")) // style - -wxEND_PROPERTIES_TABLE() - -wxBEGIN_HANDLERS_TABLE(wxButton) -wxEND_HANDLERS_TABLE() - -wxCONSTRUCTOR_6( wxButton , wxWindow* , Parent , wxWindowID , Id , wxString , Label , wxPoint , Position , wxSize , Size , long , WindowStyle ) - - -#else -IMPLEMENT_DYNAMIC_CLASS(wxButton, wxControl) -#endif - // ============================================================================ // implementation // ============================================================================ @@ -418,7 +371,7 @@ void wxMSWButton::UpdateMultilineStyle(HWND hwnd, const wxString& label) // the control unless it already has new lines in its label) long styleOld = ::GetWindowLong(hwnd, GWL_STYLE), styleNew; - if ( label.find(_T('\n')) != wxString::npos ) + if ( label.find(wxT('\n')) != wxString::npos ) styleNew = styleOld | BS_MULTILINE; else styleNew = styleOld & ~BS_MULTILINE; @@ -427,7 +380,9 @@ void wxMSWButton::UpdateMultilineStyle(HWND hwnd, const wxString& label) ::SetWindowLong(hwnd, GWL_STYLE, styleNew); } -wxSize wxMSWButton::GetFittingSize(wxWindow *win, const wxSize& sizeLabel) +wxSize wxMSWButton::GetFittingSize(wxWindow *win, + const wxSize& sizeLabel, + int flags) { // FIXME: this is pure guesswork, need to retrieve the real button margins wxSize sizeBtn = sizeLabel; @@ -435,24 +390,31 @@ wxSize wxMSWButton::GetFittingSize(wxWindow *win, const wxSize& sizeLabel) sizeBtn.x += 3*win->GetCharWidth(); sizeBtn.y = 11*EDIT_HEIGHT_FROM_CHAR_HEIGHT(sizeLabel.y)/10; + // account for the shield UAC icon if we have it + if ( flags & Size_AuthNeeded ) + sizeBtn.x += wxSystemSettings::GetMetric(wxSYS_SMALLICON_X); + return sizeBtn; } -wxSize wxMSWButton::ComputeBestSize(wxControl *btn) +wxSize wxMSWButton::ComputeBestSize(wxControl *btn, int flags) { wxClientDC dc(btn); wxSize sizeBtn; dc.GetMultiLineTextExtent(btn->GetLabelText(), &sizeBtn.x, &sizeBtn.y); - sizeBtn = GetFittingSize(btn, sizeBtn); + sizeBtn = GetFittingSize(btn, sizeBtn, flags); // all buttons have at least the standard size unless the user explicitly // wants them to be of smaller size and used wxBU_EXACTFIT style when // creating the button if ( !btn->HasFlag(wxBU_EXACTFIT) ) { - wxSize sizeDef = wxButton::GetDefaultSize(); + // The size of a standard button in the dialog units is 50x14, use it. + // Note that we intentionally don't use GetDefaultSize() here, because + // it's inexact -- dialog units depend on this dialog's font. + wxSize sizeDef = btn->ConvertDialogToPixels(wxSize(50, 14)); if ( sizeBtn.x < sizeDef.x ) sizeBtn.x = sizeDef.x; if ( sizeBtn.y < sizeDef.y ) @@ -477,6 +439,8 @@ bool wxButton::Create(wxWindow *parent, const wxValidator& validator, const wxString& name) { + m_authNeeded = false; + wxString label(lbl); if (label.empty() && wxIsStockID(id)) { @@ -504,7 +468,7 @@ bool wxButton::Create(wxWindow *parent, // value and the label is not set yet when MSWGetStyle() is called msStyle |= wxMSWButton::GetMultilineStyle(label); - return MSWCreateControl(_T("BUTTON"), msStyle, pos, size, label, exstyle); + return MSWCreateControl(wxT("BUTTON"), msStyle, pos, size, label, exstyle); } wxButton::~wxButton() @@ -565,27 +529,90 @@ void wxButton::SetLabel(const wxString& label) // size management including autosizing // ---------------------------------------------------------------------------- -wxSize wxButton::DoGetBestSize() const +void wxButton::AdjustForBitmapSize(wxSize &size) const { - wxSize size = wxMSWButton::ComputeBestSize(const_cast(this)); - if ( m_imageData ) + if ( !m_imageData ) + return; + + // 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 ) + { + size.x += sizeBmp.x; + if ( sizeBmp.y > size.y ) + size.y = sizeBmp.y; + } + else // bitmap on top/below the text + { + size.y += sizeBmp.y; + if ( sizeBmp.x > size.x ) + size.x = sizeBmp.x; + } + + // account for the user-specified margins + size += 2*m_imageData->GetBitmapMargins(); + + // and also for the margins we always add internally (unless we have no + // border at all in which case the button has exactly the same size as + // bitmap and so no margins should be used) + if ( !HasFlag(wxBORDER_NONE) ) { - const wxSize sizeBmp = m_imageData->GetBitmap(State_Normal).GetSize(); - const wxDirection dirBmp = m_imageData->GetBitmapPosition(); - if ( dirBmp == wxLEFT || dirBmp == wxRIGHT ) + int marginH = 0, + marginV = 0; +#if wxUSE_UXTHEME + if ( wxUxThemeEngine::GetIfActive() ) { - size.x += sizeBmp.x; - if ( sizeBmp.y > size.y ) - size.y = sizeBmp.y; + 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)); + + marginH = margins.cxLeftWidth + margins.cxRightWidth + + 2*XP_BUTTON_EXTRA_MARGIN; + marginV = margins.cyTopHeight + margins.cyBottomHeight + + 2*XP_BUTTON_EXTRA_MARGIN; } - else // bitmap on top/below the text + else +#endif // wxUSE_UXTHEME { - size.y += sizeBmp.y; - if ( sizeBmp.x > size.x ) - size.x = sizeBmp.x; + marginH = + marginV = OD_BUTTON_MARGIN; } - size += 2*m_imageData->GetBitmapMargins(); + size.IncBy(marginH, marginV); + } +} + +wxSize wxButton::DoGetBestSize() const +{ + wxSize size; + + // account for the text part if we have it or if we don't have any image at + // all (buttons initially created with empty label should still have a non + // zero size) + if ( ShowsLabel() || !m_imageData ) + { + int flags = 0; + if ( GetAuthNeeded() ) + flags |= wxMSWButton::Size_AuthNeeded; + + size = wxMSWButton::ComputeBestSize(const_cast(this), flags); + } + + if ( m_imageData ) + { + AdjustForBitmapSize(size); CacheBestSize(size); } @@ -603,16 +630,20 @@ wxSize wxButtonBase::GetDefaultSize() wxScreenDC dc; dc.SetFont(wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT)); - // the size of a standard button in the dialog units is 50x14, - // translate this to pixels - // NB1: the multipliers come from the Windows convention - // NB2: the extra +1/+2 were needed to get the size be the same as the - // size of the buttons in the standard dialog - I don't know how - // this happens, but on my system this size is 75x23 in pixels and - // 23*8 isn't even divisible by 14... Would be nice to understand - // why these constants are needed though! - s_sizeBtn.x = (50 * (dc.GetCharWidth() + 1))/4; - s_sizeBtn.y = ((14 * dc.GetCharHeight()) + 2)/8; + // The size of a standard button in the dialog units is 50x14, + // translate this to pixels. + // + // Windows' computes dialog units using average character width over + // upper- and lower-case ASCII alphabet and not using the average + // character width metadata stored in the font; see + // http://support.microsoft.com/default.aspx/kb/145994 for detailed + // discussion. + // + // NB: wxMulDivInt32() is used, because it correctly rounds the result + + const wxSize base = wxPrivate::GetAverageASCIILetterSize(dc); + s_sizeBtn.x = wxMulDivInt32(50, base.x, 4); + s_sizeBtn.y = wxMulDivInt32(14, base.y, 8); } return s_sizeBtn; @@ -623,6 +654,14 @@ wxSize wxButtonBase::GetDefaultSize() // ---------------------------------------------------------------------------- /* + The comment below and all this code is probably due to not using WM_NEXTDLGCTL + message when changing focus (but just SetFocus() which is not enough), see + http://blogs.msdn.com/oldnewthing/archive/2004/08/02/205624.aspx for the + full explanation. + + TODO: Do use WM_NEXTDLGCTL and get rid of all this code. + + "Everything you ever wanted to know about the default buttons" or "Why do we have to do all this?" @@ -689,10 +728,10 @@ static wxTopLevelWindow *GetTLWParentIfNotBeingDeleted(wxWindow *win) win = parent; } - wxASSERT_MSG( win, _T("button without top level parent?") ); + wxASSERT_MSG( win, wxT("button without top level parent?") ); wxTopLevelWindow * const tlw = wxDynamicCast(win, wxTopLevelWindow); - wxASSERT_MSG( tlw, _T("logic error in GetTLWParentIfNotBeingDeleted()") ); + wxASSERT_MSG( tlw, wxT("logic error in GetTLWParentIfNotBeingDeleted()") ); return tlw; } @@ -744,7 +783,7 @@ wxButton::SetDefaultStyle(wxButton *btn, bool on) return; wxWindow * const tlw = wxGetTopLevelParent(btn); - wxCHECK_RET( tlw, _T("button without top level window?") ); + wxCHECK_RET( tlw, wxT("button without top level window?") ); ::SendMessage(GetHwndOf(tlw), DM_SETDEFID, btn->GetId(), 0L); @@ -851,25 +890,51 @@ WXLRESULT wxButton::MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam) // as the theme size might have changed InvalidateBestSize(); } - else if ( wxUxThemeEngine::GetIfActive() ) +#endif // wxUSE_UXTHEME + // must use m_mouseInWindow here instead of IsMouseInWindow() + // since we need to know the first time the mouse enters the window + // and IsMouseInWindow() would return true in this case + else if ( (nMsg == WM_MOUSEMOVE && !m_mouseInWindow) || + nMsg == WM_MOUSELEAVE ) { - // we need to Refresh() if mouse has entered or left window - // so we can update the hot tracking state - // must use m_mouseInWindow here instead of IsMouseInWindow() - // since we need to know the first time the mouse enters the window - // and IsMouseInWindow() would return true in this case - if ( ( nMsg == WM_MOUSEMOVE && !m_mouseInWindow ) || - nMsg == WM_MOUSELEAVE ) + if ( + IsEnabled() && + ( +#if wxUSE_UXTHEME + wxUxThemeEngine::GetIfActive() || +#endif // wxUSE_UXTHEME + (m_imageData && m_imageData->GetBitmap(State_Current).IsOk()) + ) + ) { Refresh(); } } -#endif // wxUSE_UXTHEME // let the base class do all real processing return wxControl::MSWWindowProc(nMsg, wParam, lParam); } +// ---------------------------------------------------------------------------- +// authentication needed handling +// ---------------------------------------------------------------------------- + +bool wxButton::DoGetAuthNeeded() const +{ + return m_authNeeded; +} + +void wxButton::DoSetAuthNeeded(bool show) +{ + // show/hide UAC symbol on Windows Vista and later + if ( wxGetWinVersion() >= wxWinVersion_6 ) + { + m_authNeeded = show; + ::SendMessage(GetHwnd(), BCM_SETSHIELD, 0, show); + InvalidateBestSize(); + } +} + // ---------------------------------------------------------------------------- // button images // ---------------------------------------------------------------------------- @@ -885,23 +950,38 @@ 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 ( ShowsLabel() && wxUxThemeEngine::GetIfActive() ) { - m_imageData = new wxXPButtonImageData(this, bitmap.GetSize()); + m_imageData = new wxXPButtonImageData(this, bitmap); } else #endif // wxUSE_UXTHEME { - m_imageData = new wxODButtonImageData(this); + m_imageData = new wxODButtonImageData(this, bitmap); MakeOwnerDrawn(); } + } + else + { + m_imageData->SetBitmap(bitmap, which); + } - // if a bitmap was assigned to the bitmap, its best size must be - // changed to account for it + // it should be enough to only invalidate the best size when the normal + // bitmap changes as all bitmaps assigned to the button should be of the + // same size anyhow + if ( which == State_Normal ) InvalidateBestSize(); - } - 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) @@ -909,6 +989,7 @@ void wxButton::DoSetBitmapMargins(wxCoord x, wxCoord y) wxCHECK_RET( m_imageData, "SetBitmap() must be called first" ); m_imageData->SetBitmapMargins(x, y); + InvalidateBestSize(); } void wxButton::DoSetBitmapPosition(wxDirection dir) @@ -916,6 +997,7 @@ void wxButton::DoSetBitmapPosition(wxDirection dir) wxCHECK_RET( m_imageData, "SetBitmap() must be called first" ); m_imageData->SetBitmapPosition(dir); + InvalidateBestSize(); } // ---------------------------------------------------------------------------- @@ -926,6 +1008,25 @@ void wxButton::DoSetBitmapPosition(wxDirection dir) namespace { +// return the button state using both the ODS_XXX flags specified in state +// parameter and the current button state +wxButton::State GetButtonState(wxButton *btn, UINT state) +{ + if ( state & ODS_DISABLED ) + return wxButton::State_Disabled; + + if ( state & ODS_SELECTED ) + return wxButton::State_Pressed; + + if ( btn->HasCapture() || btn->IsMouseInWindow() ) + return wxButton::State_Current; + + if ( state & ODS_FOCUS ) + return wxButton::State_Focused; + + return wxButton::State_Normal; +} + void DrawButtonText(HDC hdc, RECT *pRect, const wxString& text, @@ -938,7 +1039,7 @@ void DrawButtonText(HDC hdc, // center text horizontally in any case flags |= DT_CENTER; - if ( text.find(_T('\n')) != wxString::npos ) + if ( text.find(wxT('\n')) != wxString::npos ) { // draw multiline label @@ -1064,49 +1165,42 @@ void DrawButtonFrame(HDC hdc, RECT& rectBtn, } #if wxUSE_UXTHEME -void MSWDrawXPBackground(wxButton *button, HDC hdc, RECT& rectBtn, UINT state) +void DrawXPBackground(wxButton *button, HDC hdc, RECT& rectBtn, UINT state) { 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 ) + // this array is indexed by wxButton::State values and so must be kept in + // sync with it + static const int uxStates[] = { - iState = PBS_DEFAULTED; - } - else if ( state & ODS_DISABLED ) - { - iState = PBS_DISABLED; - } - else - { - iState = PBS_NORMAL; - } + 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 ( wxUxThemeEngine::Get()->IsThemeBackgroundPartiallyTransparent(theme, - BP_PUSHBUTTON, - iState) ) + if ( engine->IsThemeBackgroundPartiallyTransparent + ( + theme, + BP_PUSHBUTTON, + iState + ) ) { - wxUxThemeEngine::Get()->DrawThemeParentBackground(GetHwndOf(button), hdc, &rectBtn); + engine->DrawThemeParentBackground(GetHwndOf(button), hdc, &rectBtn); } // draw background - wxUxThemeEngine::Get()->DrawThemeBackground(theme, hdc, BP_PUSHBUTTON, iState, - &rectBtn, NULL); + engine->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); + 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() ) { @@ -1181,48 +1275,51 @@ bool wxButton::MSWOnDraw(WXDRAWITEMSTRUCT *wxdis) CopyRect(&rectBtn, &lpDIS->rcItem); // draw the button background -#if wxUSE_UXTHEME - if ( wxUxThemeEngine::GetIfActive() ) + if ( !HasFlag(wxBORDER_NONE) ) { - MSWDrawXPBackground(this, hdc, rectBtn, state); - } - else +#if wxUSE_UXTHEME + if ( wxUxThemeEngine::GetIfActive() ) + { + DrawXPBackground(this, hdc, rectBtn, state); + } + else #endif // wxUSE_UXTHEME - { - COLORREF colBg = wxColourToRGB(GetBackgroundColour()); + { + COLORREF colBg = wxColourToRGB(GetBackgroundColour()); - // first, draw the background - AutoHBRUSH hbrushBackground(colBg); - FillRect(hdc, &rectBtn, hbrushBackground); + // 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 ) + // draw the border for the current state + bool selected = (state & ODS_SELECTED) != 0; + if ( !selected ) { - selected = tlw->GetDefaultItem() == this; + wxTopLevelWindow * + tlw = wxDynamicCast(wxGetTopLevelParent(this), wxTopLevelWindow); + if ( tlw ) + { + selected = tlw->GetDefaultItem() == this; + } } - } - DrawButtonFrame(hdc, rectBtn, selected, pushed); - } + DrawButtonFrame(hdc, rectBtn, selected, pushed); + } - // draw the focus rectangle if we need it - if ( (state & ODS_FOCUS) && !(state & ODS_NOFOCUSRECT) ) - { - DrawFocusRect(hdc, &rectBtn); + // draw the focus rectangle if we need it + if ( (state & ODS_FOCUS) && !(state & ODS_NOFOCUSRECT) ) + { + DrawFocusRect(hdc, &rectBtn); #if wxUSE_UXTHEME - if ( !wxUxThemeEngine::GetIfActive() ) + if ( !wxUxThemeEngine::GetIfActive() ) #endif // wxUSE_UXTHEME - { - if ( pushed ) { - // the label is shifted by 1 pixel to create "pushed" effect - OffsetRect(&rectBtn, 1, 1); + if ( pushed ) + { + // the label is shifted by 1 pixel to create "pushed" effect + OffsetRect(&rectBtn, 1, 1); + } } } } @@ -1231,7 +1328,10 @@ bool wxButton::MSWOnDraw(WXDRAWITEMSTRUCT *wxdis) // draw the image, if any if ( m_imageData ) { - wxBitmap bmp = m_imageData->GetBitmap(State_Normal); + 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); @@ -1240,33 +1340,38 @@ bool wxButton::MSWOnDraw(WXDRAWITEMSTRUCT *wxdis) // for simplicity, we start with centred rectangle and then move it to // the appropriate edge wxRect rectBitmap = wxRect(sizeBmp).CentreIn(rectButton); - 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; + // 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); @@ -1277,15 +1382,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 ( 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; }