implement support for per-state bitmaps in wxMSW wxButton

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@61067 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Vadim Zeitlin
2009-06-15 20:18:10 +00:00
parent b879becf6a
commit d5b98eb928
2 changed files with 126 additions and 95 deletions

View File

@@ -121,18 +121,18 @@ protected:
// ------------ // ------------
// the check/radio boxes for styles // the check/radio boxes for styles
wxCheckBox *m_chkBitmap, wxCheckBox *m_chkBitmapOnly,
*m_chkImage, *m_chkTextAndBitmap,
*m_chkFit, *m_chkFit,
*m_chkDefault; *m_chkDefault;
// more checkboxes for wxBitmapButton only // more checkboxes for wxBitmapButton only
wxCheckBox *m_chkUseSelected, wxCheckBox *m_chkUsePressed,
*m_chkUseFocused, *m_chkUseFocused,
*m_chkUseHover, *m_chkUseCurrent,
*m_chkUseDisabled; *m_chkUseDisabled;
// and an image position choice used if m_chkImage is on // and an image position choice used if m_chkTextAndBitmap is on
wxRadioBox *m_radioImagePos; wxRadioBox *m_radioImagePos;
wxRadioBox *m_radioHAlign, wxRadioBox *m_radioHAlign,
@@ -181,13 +181,13 @@ ButtonWidgetsPage::ButtonWidgetsPage(WidgetsBookCtrl *book,
: WidgetsPage(book, imaglist, button_xpm) : WidgetsPage(book, imaglist, button_xpm)
{ {
// init everything // init everything
m_chkBitmap = m_chkBitmapOnly =
m_chkImage = m_chkTextAndBitmap =
m_chkFit = m_chkFit =
m_chkDefault = m_chkDefault =
m_chkUseSelected = m_chkUsePressed =
m_chkUseFocused = m_chkUseFocused =
m_chkUseHover = m_chkUseCurrent =
m_chkUseDisabled = (wxCheckBox *)NULL; m_chkUseDisabled = (wxCheckBox *)NULL;
m_radioImagePos = m_radioImagePos =
@@ -209,19 +209,24 @@ void ButtonWidgetsPage::CreateContent()
wxSizer *sizerLeft = new wxStaticBoxSizer(box, wxVERTICAL); wxSizer *sizerLeft = new wxStaticBoxSizer(box, wxVERTICAL);
m_chkBitmap = CreateCheckBoxAndAddToSizer(sizerLeft, _T("&Bitmap button")); m_chkBitmapOnly = CreateCheckBoxAndAddToSizer(sizerLeft, "&Bitmap only");
m_chkImage = CreateCheckBoxAndAddToSizer(sizerLeft, _T("With &image")); m_chkTextAndBitmap = CreateCheckBoxAndAddToSizer(sizerLeft, "Text &and &bitmap");
m_chkFit = CreateCheckBoxAndAddToSizer(sizerLeft, _T("&Fit exactly")); m_chkFit = CreateCheckBoxAndAddToSizer(sizerLeft, _T("&Fit exactly"));
m_chkDefault = CreateCheckBoxAndAddToSizer(sizerLeft, _T("&Default")); m_chkDefault = CreateCheckBoxAndAddToSizer(sizerLeft, _T("&Default"));
sizerLeft->AddSpacer(5); sizerLeft->AddSpacer(5);
wxSizer *sizerUseLabels = wxSizer *sizerUseLabels =
new wxStaticBoxSizer(wxVERTICAL, this, _T("&Use the following bitmaps?")); new wxStaticBoxSizer(wxVERTICAL, this,
m_chkUseSelected = CreateCheckBoxAndAddToSizer(sizerUseLabels, _T("&Pushed")); "&Use the following bitmaps in addition to the normal one?");
m_chkUseFocused = CreateCheckBoxAndAddToSizer(sizerUseLabels, _T("&Focused")); m_chkUsePressed = CreateCheckBoxAndAddToSizer(sizerUseLabels,
m_chkUseHover = CreateCheckBoxAndAddToSizer(sizerUseLabels, _T("&Hover")); "&Pressed (small help icon)");
m_chkUseDisabled = CreateCheckBoxAndAddToSizer(sizerUseLabels, _T("&Disabled")); m_chkUseFocused = CreateCheckBoxAndAddToSizer(sizerUseLabels,
"&Focused (small error icon)");
m_chkUseCurrent = CreateCheckBoxAndAddToSizer(sizerUseLabels,
"&Current (small warning icon)");
m_chkUseDisabled = CreateCheckBoxAndAddToSizer(sizerUseLabels,
"&Disabled (broken image icon)");
sizerLeft->Add(sizerUseLabels, wxSizerFlags().Expand().Border()); sizerLeft->Add(sizerUseLabels, wxSizerFlags().Expand().Border());
sizerLeft->AddSpacer(10); sizerLeft->AddSpacer(10);
@@ -300,14 +305,14 @@ void ButtonWidgetsPage::CreateContent()
void ButtonWidgetsPage::Reset() void ButtonWidgetsPage::Reset()
{ {
m_chkBitmap->SetValue(false); m_chkBitmapOnly->SetValue(false);
m_chkFit->SetValue(true); m_chkFit->SetValue(true);
m_chkImage->SetValue(false); m_chkTextAndBitmap->SetValue(false);
m_chkDefault->SetValue(false); m_chkDefault->SetValue(false);
m_chkUseSelected->SetValue(true); m_chkUsePressed->SetValue(true);
m_chkUseFocused->SetValue(true); m_chkUseFocused->SetValue(true);
m_chkUseHover->SetValue(true); m_chkUseCurrent->SetValue(true);
m_chkUseDisabled->SetValue(true); m_chkUseDisabled->SetValue(true);
m_radioImagePos->SetSelection(ButtonImagePos_Left); m_radioImagePos->SetSelection(ButtonImagePos_Left);
@@ -376,17 +381,19 @@ void ButtonWidgetsPage::CreateButton()
break; break;
} }
const bool isBitmapButton = m_chkBitmap->GetValue(); bool showsBitmap = false;
if ( isBitmapButton ) if ( m_chkBitmapOnly->GetValue() )
{ {
showsBitmap = true;
wxBitmapButton *bbtn = new wxBitmapButton(this, ButtonPage_Button, wxBitmapButton *bbtn = new wxBitmapButton(this, ButtonPage_Button,
CreateBitmap(_T("normal"))); CreateBitmap(_T("normal")));
if ( m_chkUseSelected->GetValue() ) if ( m_chkUsePressed->GetValue() )
bbtn->SetBitmapSelected(CreateBitmap(_T("pushed"))); bbtn->SetBitmapPressed(CreateBitmap(_T("pushed")));
if ( m_chkUseFocused->GetValue() ) if ( m_chkUseFocused->GetValue() )
bbtn->SetBitmapFocus(CreateBitmap(_T("focused"))); bbtn->SetBitmapFocus(CreateBitmap(_T("focused")));
if ( m_chkUseHover->GetValue() ) if ( m_chkUseCurrent->GetValue() )
bbtn->SetBitmapHover(CreateBitmap(_T("hover"))); bbtn->SetBitmapCurrent(CreateBitmap(_T("hover")));
if ( m_chkUseDisabled->GetValue() ) if ( m_chkUseDisabled->GetValue() )
bbtn->SetBitmapDisabled(CreateBitmap(_T("disabled"))); bbtn->SetBitmapDisabled(CreateBitmap(_T("disabled")));
m_button = bbtn; m_button = bbtn;
@@ -398,13 +405,10 @@ void ButtonWidgetsPage::CreateButton()
flags); flags);
} }
m_chkUseSelected->Enable(isBitmapButton); if ( !showsBitmap && m_chkTextAndBitmap->GetValue() )
m_chkUseFocused->Enable(isBitmapButton);
m_chkUseHover->Enable(isBitmapButton);
m_chkUseDisabled->Enable(isBitmapButton);
if ( m_chkImage->GetValue() )
{ {
showsBitmap = true;
static const wxDirection positions[] = static const wxDirection positions[] =
{ {
wxLEFT, wxRIGHT, wxTOP, wxBOTTOM wxLEFT, wxRIGHT, wxTOP, wxBOTTOM
@@ -412,8 +416,22 @@ void ButtonWidgetsPage::CreateButton()
m_button->SetBitmap(wxArtProvider::GetIcon(wxART_INFORMATION), m_button->SetBitmap(wxArtProvider::GetIcon(wxART_INFORMATION),
positions[m_radioImagePos->GetSelection()]); positions[m_radioImagePos->GetSelection()]);
if ( m_chkUsePressed->GetValue() )
m_button->SetBitmapPressed(wxArtProvider::GetIcon(wxART_HELP));
if ( m_chkUseFocused->GetValue() )
m_button->SetBitmapFocus(wxArtProvider::GetIcon(wxART_ERROR));
if ( m_chkUseCurrent->GetValue() )
m_button->SetBitmapCurrent(wxArtProvider::GetIcon(wxART_WARNING));
if ( m_chkUseDisabled->GetValue() )
m_button->SetBitmapDisabled(wxArtProvider::GetIcon(wxART_MISSING_IMAGE));
} }
m_chkUsePressed->Enable(showsBitmap);
m_chkUseFocused->Enable(showsBitmap);
m_chkUseCurrent->Enable(showsBitmap);
m_chkUseDisabled->Enable(showsBitmap);
if ( m_chkDefault->GetValue() ) if ( m_chkDefault->GetValue() )
{ {
m_button->SetDefault(); m_button->SetDefault();

View File

@@ -137,8 +137,10 @@ const int OD_BUTTON_MARGIN = 4;
class wxODButtonImageData : public wxButtonImageData class wxODButtonImageData : public wxButtonImageData
{ {
public: public:
wxODButtonImageData(wxButton *btn) wxODButtonImageData(wxButton *btn, const wxBitmap& bitmap)
{ {
SetBitmap(bitmap, wxButton::State_Normal);
m_dir = wxLEFT; m_dir = wxLEFT;
m_margin.x = btn->GetCharWidth(); m_margin.x = btn->GetCharWidth();
@@ -192,10 +194,17 @@ class wxXPButtonImageData : public wxButtonImageData
public: public:
// we must be constructed with the size of our images as we need to create // we must be constructed with the size of our images as we need to create
// the image list // the image list
wxXPButtonImageData(wxButton *btn, const wxSize& size) wxXPButtonImageData(wxButton *btn, const wxBitmap& bitmap)
: m_iml(size.x, size.y, true /* use mask */, wxButton::State_Max), : m_iml(bitmap.GetWidth(), bitmap.GetHeight(), true /* use mask */,
wxButton::State_Max),
m_hwndBtn(GetHwndOf(btn)) 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); m_data.himl = GetHimagelistOf(&m_iml);
// use default margins // use default margins
@@ -215,22 +224,7 @@ public:
virtual void SetBitmap(const wxBitmap& bitmap, wxButton::State which) virtual void SetBitmap(const wxBitmap& bitmap, wxButton::State which)
{ {
const int imagesToAdd = which - m_iml.GetImageCount(); m_iml.Replace(which, bitmap);
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);
}
UpdateImageInfo(); UpdateImageInfo();
} }
@@ -851,20 +845,23 @@ WXLRESULT wxButton::MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam)
// as the theme size might have changed // as the theme size might have changed
InvalidateBestSize(); 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 if (
// so we can update the hot tracking state #if wxUSE_UXTHEME
// must use m_mouseInWindow here instead of IsMouseInWindow() wxUxThemeEngine::GetIfActive() ||
// since we need to know the first time the mouse enters the window #endif // wxUSE_UXTHEME
// and IsMouseInWindow() would return true in this case m_imageData && m_imageData->GetBitmap(State_Current).IsOk()
if ( ( nMsg == WM_MOUSEMOVE && !m_mouseInWindow ) || )
nMsg == WM_MOUSELEAVE )
{ {
Refresh(); Refresh();
} }
} }
#endif // wxUSE_UXTHEME
// let the base class do all real processing // let the base class do all real processing
return wxControl::MSWWindowProc(nMsg, wParam, lParam); return wxControl::MSWWindowProc(nMsg, wParam, lParam);
@@ -887,12 +884,12 @@ void wxButton::DoSetBitmap(const wxBitmap& bitmap, State which)
#if wxUSE_UXTHEME #if wxUSE_UXTHEME
if ( wxUxThemeEngine::GetIfActive() ) if ( wxUxThemeEngine::GetIfActive() )
{ {
m_imageData = new wxXPButtonImageData(this, bitmap.GetSize()); m_imageData = new wxXPButtonImageData(this, bitmap);
} }
else else
#endif // wxUSE_UXTHEME #endif // wxUSE_UXTHEME
{ {
m_imageData = new wxODButtonImageData(this); m_imageData = new wxODButtonImageData(this, bitmap);
MakeOwnerDrawn(); MakeOwnerDrawn();
} }
@@ -900,8 +897,10 @@ void wxButton::DoSetBitmap(const wxBitmap& bitmap, State which)
// changed to account for it // changed to account for it
InvalidateBestSize(); InvalidateBestSize();
} }
else
m_imageData->SetBitmap(bitmap, which); {
m_imageData->SetBitmap(bitmap, which);
}
} }
void wxButton::DoSetBitmapMargins(wxCoord x, wxCoord y) void wxButton::DoSetBitmapMargins(wxCoord x, wxCoord y)
@@ -926,6 +925,25 @@ void wxButton::DoSetBitmapPosition(wxDirection dir)
namespace 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, void DrawButtonText(HDC hdc,
RECT *pRect, RECT *pRect,
const wxString& text, const wxString& text,
@@ -1064,48 +1082,40 @@ void DrawButtonFrame(HDC hdc, RECT& rectBtn,
} }
#if wxUSE_UXTHEME #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"); wxUxThemeHandle theme(button, L"BUTTON");
int iState;
if ( state & ODS_SELECTED ) // this array is indexed by wxButton::State values and so must be kept in
// sync with it
static const uxStates[] =
{ {
iState = PBS_PRESSED; PBS_NORMAL, PBS_HOT, PBS_PRESSED, PBS_DISABLED, PBS_DEFAULTED
} };
else if ( button->HasCapture() || button->IsMouseInWindow() )
{ int iState = uxStates[GetButtonState(button, state)];
iState = PBS_HOT;
} wxUxThemeEngine * const engine = wxUxThemeEngine::Get();
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 // draw parent background if needed
if ( wxUxThemeEngine::Get()->IsThemeBackgroundPartiallyTransparent(theme, if ( engine->IsThemeBackgroundPartiallyTransparent
BP_PUSHBUTTON, (
iState) ) theme,
BP_PUSHBUTTON,
iState
) )
{ {
wxUxThemeEngine::Get()->DrawThemeParentBackground(GetHwndOf(button), hdc, &rectBtn); engine->DrawThemeParentBackground(GetHwndOf(button), hdc, &rectBtn);
} }
// draw background // draw background
wxUxThemeEngine::Get()->DrawThemeBackground(theme, hdc, BP_PUSHBUTTON, iState, engine->DrawThemeBackground(theme, hdc, BP_PUSHBUTTON, iState,
&rectBtn, NULL); &rectBtn, NULL);
// calculate content area margins // calculate content area margins
MARGINS margins; MARGINS margins;
wxUxThemeEngine::Get()->GetThemeMargins(theme, hdc, BP_PUSHBUTTON, iState, engine->GetThemeMargins(theme, hdc, BP_PUSHBUTTON, iState,
TMT_CONTENTMARGINS, &rectBtn, &margins); TMT_CONTENTMARGINS, &rectBtn, &margins);
::InflateRect(&rectBtn, -margins.cxLeftWidth, -margins.cyTopHeight); ::InflateRect(&rectBtn, -margins.cxLeftWidth, -margins.cyTopHeight);
if ( button->UseBgCol() ) if ( button->UseBgCol() )
@@ -1184,7 +1194,7 @@ bool wxButton::MSWOnDraw(WXDRAWITEMSTRUCT *wxdis)
#if wxUSE_UXTHEME #if wxUSE_UXTHEME
if ( wxUxThemeEngine::GetIfActive() ) if ( wxUxThemeEngine::GetIfActive() )
{ {
MSWDrawXPBackground(this, hdc, rectBtn, state); DrawXPBackground(this, hdc, rectBtn, state);
} }
else else
#endif // wxUSE_UXTHEME #endif // wxUSE_UXTHEME
@@ -1231,7 +1241,10 @@ bool wxButton::MSWOnDraw(WXDRAWITEMSTRUCT *wxdis)
// draw the image, if any // draw the image, if any
if ( m_imageData ) 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 sizeBmp = bmp.GetSize();
const wxSize margin = m_imageData->GetBitmapMargins(); const wxSize margin = m_imageData->GetBitmapMargins();
const wxSize sizeBmpWithMargins(sizeBmp + 2*margin); const wxSize sizeBmpWithMargins(sizeBmp + 2*margin);