X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/e431c7df61e57e2e55e20c3fe8e479bd635739d8..e3778b4d9c7eebc39f496a9dd055638e06fb9140:/src/msw/button.cpp diff --git a/src/msw/button.cpp b/src/msw/button.cpp index c81472bebc..10bb135fb5 100644 --- a/src/msw/button.cpp +++ b/src/msw/button.cpp @@ -37,13 +37,20 @@ #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" + +#if wxUSE_MARKUP + #include "wx/generic/private/markuptext.h" +#endif // wxUSE_MARKUP using namespace wxMSWImpl; @@ -102,6 +109,16 @@ 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 + +#if wxUSE_UXTHEME +extern wxWindowMSW *wxWindowBeingErased; // From src/msw/window.cpp +#endif // wxUSE_UXTHEME + // ---------------------------------------------------------------------------- // button image data // ---------------------------------------------------------------------------- @@ -140,6 +157,7 @@ public: wxODButtonImageData(wxButton *btn, const wxBitmap& bitmap) { SetBitmap(bitmap, wxButton::State_Normal); + SetBitmap(bitmap.ConvertToDisabled(), wxButton::State_Disabled); m_dir = wxLEFT; @@ -208,21 +226,22 @@ public: wxButton::State_Max), m_hwndBtn(GetHwndOf(btn)) { - // initialize all bitmaps to normal state + // initialize all bitmaps except for the disabled one to normal state for ( int n = 0; n < wxButton::State_Max; n++ ) { - m_iml.Add(bitmap); + m_iml.Add(n == wxButton::State_Disabled ? bitmap.ConvertToDisabled() + : bitmap); } m_data.himl = GetHimagelistOf(&m_iml); - // use default margins + // no margins by default m_data.margin.left = - m_data.margin.right = btn->GetCharWidth(); + m_data.margin.right = m_data.margin.top = - m_data.margin.bottom = btn->GetCharHeight() / 2; + m_data.margin.bottom = 0; - // and default alignment + // use default alignment m_data.uAlign = BUTTON_IMAGELIST_ALIGN_LEFT; UpdateImageInfo(); @@ -345,67 +364,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 // ============================================================================ @@ -432,37 +390,58 @@ 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; sizeBtn.x += 3*win->GetCharWidth(); - sizeBtn.y = 11*EDIT_HEIGHT_FROM_CHAR_HEIGHT(sizeLabel.y)/10; + sizeBtn.y += win->GetCharHeight()/2; + + // 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::ComputeBestFittingSize(wxControl *btn, int flags) { wxClientDC dc(btn); wxSize sizeBtn; dc.GetMultiLineTextExtent(btn->GetLabelText(), &sizeBtn.x, &sizeBtn.y); - sizeBtn = GetFittingSize(btn, sizeBtn); + return GetFittingSize(btn, sizeBtn, flags); +} + +wxSize wxMSWButton::IncreaseToStdSizeAndCache(wxControl *btn, const wxSize& size) +{ + wxSize sizeBtn(size); + + // All buttons have at least the standard height and, unless the user + // explicitly wants them to be as small as possible and used wxBU_EXACTFIT + // style to indicate this, of at least the standard width too. + // + // Notice that we really want to make all buttons equally high, otherwise + // they look ugly and the existing code using wxBU_EXACTFIT only uses it to + // control width and not height. - // 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 + // The 50x14 button size is documented in the "Recommended sizing and + // spacing" section of MSDN layout article. + // + // Note that we intentionally don't use GetDefaultSize() here, because + // it's inexact -- dialog units depend on this dialog's font. + const wxSize sizeDef = btn->ConvertDialogToPixels(wxSize(50, 14)); if ( !btn->HasFlag(wxBU_EXACTFIT) ) { - wxSize sizeDef = wxButton::GetDefaultSize(); if ( sizeBtn.x < sizeDef.x ) sizeBtn.x = sizeDef.x; - if ( sizeBtn.y < sizeDef.y ) - sizeBtn.y = sizeDef.y; } + if ( sizeBtn.y < sizeDef.y ) + sizeBtn.y = sizeDef.y; btn->CacheBestSize(sizeBtn); @@ -521,6 +500,9 @@ wxButton::~wxButton() } delete m_imageData; +#if wxUSE_MARKUP + delete m_markupText; +#endif // wxUSE_MARKUP } // ---------------------------------------------------------------------------- @@ -536,7 +518,7 @@ WXDWORD wxButton::MSWGetStyle(long style, WXDWORD *exstyle) const ); // we must use WS_CLIPSIBLINGS with the buttons or they would draw over - // each other in any resizeable dialog which has more than one button in + // each other in any resizable dialog which has more than one button in // the bottom msStyle |= WS_CLIPSIBLINGS; @@ -564,87 +546,125 @@ void wxButton::SetLabel(const wxString& label) wxMSWButton::UpdateMultilineStyle(GetHwnd(), label); wxButtonBase::SetLabel(label); + +#if wxUSE_MARKUP + // If we have a plain text label, we shouldn't be using markup any longer. + if ( m_markupText ) + { + delete m_markupText; + m_markupText = NULL; + + // Unfortunately we don't really know whether we can reset the button + // to be non-owner-drawn or not: if we had made it owner-drawn just + // because of a call to SetLabelMarkup(), we could, but not if there + // were [also] calls to Set{Fore,Back}groundColour(). If it's really a + // problem to have button remain owner-drawn forever just because it + // had markup label once, we should record the reason for our current + // owner-drawnness and check it here. + } +#endif // wxUSE_MARKUP } // ---------------------------------------------------------------------------- // size management including autosizing // ---------------------------------------------------------------------------- -wxSize wxButton::DoGetBestSize() const +void wxButton::AdjustForBitmapSize(wxSize &size) const { - wxSize size; + wxCHECK_RET( m_imageData, wxT("shouldn't be called if no image") ); - // account for the text part - if ( ShowsLabel() ) + // 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 = wxMSWButton::ComputeBestSize(const_cast(this)); + 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; } - if ( m_imageData ) + // 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) ) { - // 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 ) + 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; } - // account for the user-specified margins - size += 2*m_imageData->GetBitmapMargins(); + size.IncBy(marginH, marginV); + } +} - // 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) ) - { - 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)); - - 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; - } +wxSize wxButton::DoGetBestSize() const +{ + wxButton * const self = const_cast(this); - size.IncBy(marginH, marginV); - } + wxSize size; - CacheBestSize(size); + // Account for the text part if we have it. + if ( ShowsLabel() ) + { + int flags = 0; + if ( GetAuthNeeded() ) + flags |= wxMSWButton::Size_AuthNeeded; + +#if wxUSE_MARKUP + if ( m_markupText ) + { + wxClientDC dc(self); + size = wxMSWButton::GetFittingSize(self, + m_markupText->Measure(dc), + flags); + } + else // Normal plain text (but possibly multiline) label. +#endif // wxUSE_MARKUP + { + size = wxMSWButton::ComputeBestFittingSize(self, flags); + } } - return size; + if ( m_imageData ) + AdjustForBitmapSize(size); + + return wxMSWButton::IncreaseToStdSizeAndCache(self, size); } /* static */ @@ -657,16 +677,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; @@ -677,6 +701,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?" @@ -918,7 +950,7 @@ WXLRESULT wxButton::MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam) #if wxUSE_UXTHEME wxUxThemeEngine::GetIfActive() || #endif // wxUSE_UXTHEME - m_imageData && m_imageData->GetBitmap(State_Current).IsOk() + (m_imageData && m_imageData->GetBitmap(State_Current).IsOk()) ) ) { @@ -930,6 +962,26 @@ WXLRESULT wxButton::MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam) 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 // ---------------------------------------------------------------------------- @@ -941,6 +993,30 @@ wxBitmap wxButton::DoGetBitmap(State which) const void wxButton::DoSetBitmap(const wxBitmap& bitmap, State which) { +#if wxUSE_UXTHEME + wxXPButtonImageData *oldData = NULL; +#endif // wxUSE_UXTHEME + + // Check if we already had bitmaps of different size. + if ( m_imageData && + bitmap.GetSize() != m_imageData->GetBitmap(State_Normal).GetSize() ) + { + wxASSERT_MSG( which == State_Normal, + "Must set normal bitmap with the new size first" ); + +#if wxUSE_UXTHEME + if ( ShowsLabel() && wxUxThemeEngine::GetIfActive() ) + { + // We can't change the size of the images stored in wxImageList + // in wxXPButtonImageData::m_iml so force recreating it below but + // keep the current data to copy its values into the new one. + oldData = static_cast(m_imageData); + m_imageData = NULL; + } +#endif // wxUSE_UXTHEME + //else: wxODButtonImageData doesn't require anything special + } + // allocate the image data when the first bitmap is set if ( !m_imageData ) { @@ -952,6 +1028,20 @@ void wxButton::DoSetBitmap(const wxBitmap& bitmap, State which) if ( ShowsLabel() && wxUxThemeEngine::GetIfActive() ) { m_imageData = new wxXPButtonImageData(this, bitmap); + + if ( oldData ) + { + // Preserve the old values in case the user changed them. + m_imageData->SetBitmapPosition(oldData->GetBitmapPosition()); + + const wxSize oldMargins = oldData->GetBitmapMargins(); + m_imageData->SetBitmapMargins(oldMargins.x, oldMargins.y); + + // No need to preserve the bitmaps though as they were of wrong + // size anyhow. + + delete oldData; + } } else #endif // wxUSE_UXTHEME @@ -984,6 +1074,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) @@ -991,8 +1082,38 @@ void wxButton::DoSetBitmapPosition(wxDirection dir) wxCHECK_RET( m_imageData, "SetBitmap() must be called first" ); m_imageData->SetBitmapPosition(dir); + InvalidateBestSize(); } +// ---------------------------------------------------------------------------- +// markup support +// ---------------------------------------------------------------------------- + +#if wxUSE_MARKUP + +bool wxButton::DoSetLabelMarkup(const wxString& markup) +{ + if ( !wxButtonBase::DoSetLabelMarkup(markup) ) + return false; + + if ( !m_markupText ) + { + m_markupText = new wxMarkupText(markup); + MakeOwnerDrawn(); + } + else + { + // We are already owner-drawn so just update the text. + m_markupText->SetMarkup(markup); + } + + Refresh(); + + return true; +} + +#endif // wxUSE_MARKUP + // ---------------------------------------------------------------------------- // owner-drawn buttons support // ---------------------------------------------------------------------------- @@ -1022,20 +1143,18 @@ wxButton::State GetButtonState(wxButton *btn, UINT state) void DrawButtonText(HDC hdc, RECT *pRect, - const wxString& text, - COLORREF col, + wxButton *btn, int flags) { - wxTextColoursChanger changeFg(hdc, col, CLR_INVALID); - wxBkModeChanger changeBkMode(hdc, wxBRUSHSTYLE_TRANSPARENT); - - // center text horizontally in any case - flags |= DT_CENTER; + const wxString text = btn->GetLabel(); 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); @@ -1054,10 +1173,31 @@ void DrawButtonText(HDC hdc, } else // single line label { - // centre text vertically too (notice that we must have DT_SINGLELINE - // for DT_VCENTER to work) + // 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.wx_str(), text.length(), pRect, - flags | DT_SINGLELINE | DT_VCENTER); + flags | DT_SINGLELINE ); } } @@ -1181,7 +1321,20 @@ void DrawXPBackground(wxButton *button, HDC hdc, RECT& rectBtn, UINT state) iState ) ) { + // Set this button as the one whose background is being erased: this + // allows our WM_ERASEBKGND handler used by DrawThemeParentBackground() + // to correctly align the background brush with this window instead of + // the parent window to which WM_ERASEBKGND is sent. Notice that this + // doesn't work with custom user-defined EVT_ERASE_BACKGROUND handlers + // as they won't be aligned but unfortunately all the attempts to fix + // it by shifting DC origin before calling DrawThemeParentBackground() + // failed to work so we at least do this, even though this is far from + // being the perfect solution. + wxWindowBeingErased = button; + engine->DrawThemeParentBackground(GetHwndOf(button), hdc, &rectBtn); + + wxWindowBeingErased = NULL; } // draw background @@ -1333,33 +1486,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); @@ -1376,11 +1534,30 @@ bool wxButton::MSWOnDraw(WXDRAWITEMSTRUCT *wxdis) ? ::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); + wxTextColoursChanger changeFg(hdc, colFg, CLR_INVALID); + wxBkModeChanger changeBkMode(hdc, wxBRUSHSTYLE_TRANSPARENT); + +#if wxUSE_MARKUP + if ( m_markupText ) + { + wxDCTemp dc((WXHDC)hdc); + dc.SetTextForeground(wxColour(colFg)); + dc.SetFont(GetFont()); + + m_markupText->Render(dc, wxRectFromRECT(rectBtn), + state & ODS_NOACCEL + ? wxMarkupText::Render_Default + : wxMarkupText::Render_ShowAccels); + } + else // Plain text label +#endif // wxUSE_MARKUP + { + // 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, this, + state & ODS_NOACCEL ? DT_HIDEPREFIX : 0); + } } return true;