#define BCM_SETSHIELD 0x160c
#endif
+#if wxUSE_UXTHEME
+extern wxWindowMSW *wxWindowBeingErased; // From src/msw/window.cpp
+#endif // wxUSE_UXTHEME
+
// ----------------------------------------------------------------------------
// button image data
// ----------------------------------------------------------------------------
wxODButtonImageData(wxButton *btn, const wxBitmap& bitmap)
{
SetBitmap(bitmap, wxButton::State_Normal);
+ SetBitmap(bitmap.ConvertToDisabled(), wxButton::State_Disabled);
m_dir = wxLEFT;
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);
);
// 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;
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<wxXPButtonImageData *>(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 )
{
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
void DrawButtonText(HDC hdc,
RECT *pRect,
- const wxString& text,
+ wxButton *btn,
int flags)
{
- // 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);
}
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 );
}
}
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
// 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(),
+ DrawButtonText(hdc, &rectBtn, this,
state & ODS_NOACCEL ? DT_HIDEPREFIX : 0);
}
}