X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/46e3b70f200c75afe308cc10123e513cd0227265..e3778b4d9c7eebc39f496a9dd055638e06fb9140:/src/msw/button.cpp diff --git a/src/msw/button.cpp b/src/msw/button.cpp index 75d983e98d..10bb135fb5 100644 --- a/src/msw/button.cpp +++ b/src/msw/button.cpp @@ -48,6 +48,10 @@ #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; #if wxUSE_UXTHEME @@ -111,6 +115,10 @@ using namespace wxMSWImpl; #define BCM_SETSHIELD 0x160c #endif +#if wxUSE_UXTHEME +extern wxWindowMSW *wxWindowBeingErased; // From src/msw/window.cpp +#endif // wxUSE_UXTHEME + // ---------------------------------------------------------------------------- // button image data // ---------------------------------------------------------------------------- @@ -149,6 +157,7 @@ public: wxODButtonImageData(wxButton *btn, const wxBitmap& bitmap) { SetBitmap(bitmap, wxButton::State_Normal); + SetBitmap(bitmap.ConvertToDisabled(), wxButton::State_Disabled); m_dir = wxLEFT; @@ -217,10 +226,11 @@ 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); @@ -490,6 +500,9 @@ wxButton::~wxButton() } delete m_imageData; +#if wxUSE_MARKUP + delete m_markupText; +#endif // wxUSE_MARKUP } // ---------------------------------------------------------------------------- @@ -505,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; @@ -533,6 +546,23 @@ 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 } // ---------------------------------------------------------------------------- @@ -616,7 +646,19 @@ wxSize wxButton::DoGetBestSize() const if ( GetAuthNeeded() ) flags |= wxMSWButton::Size_AuthNeeded; - size = wxMSWButton::ComputeBestFittingSize(self, flags); +#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); + } } if ( m_imageData ) @@ -951,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 ) { @@ -962,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 @@ -1005,6 +1085,35 @@ void wxButton::DoSetBitmapPosition(wxDirection 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 // ---------------------------------------------------------------------------- @@ -1034,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); @@ -1066,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 ); } } @@ -1193,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 @@ -1393,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;