// set the image position relative to the text, i.e. wxLEFT means that the
// image is to the left of the text (this is the default)
- virtual void SetBitmapPosition(wxDirection WXUNUSED(dir)) { }
+ void SetBitmapPosition(wxDirection dir);
// make this button the default button in its top level window
void SetBitmapSelected(const wxBitmap& bitmap) { SetBitmapPressed(bitmap); }
void SetBitmapHover(const wxBitmap& bitmap) { SetBitmapCurrent(bitmap); }
-protected:
- // choose the default border for this window
- virtual wxBorder GetDefaultBorder() const { return wxBORDER_NONE; }
+ // this enum is not part of wx public API, it is public because it is used
+ // in non wxButton-derived classes internally
+ //
+ // also notice that MSW code relies on the values of the enum elements, do
+ // not change them without revising src/msw/button.cpp
enum State
{
State_Normal,
- State_Pressed, // a.k.a. "selected" in public API for some reason
State_Current, // a.k.a. hot or "hovering"
+ State_Pressed, // a.k.a. "selected" in public API for some reason
State_Disabled,
State_Focused,
State_Max
};
+protected:
+ // choose the default border for this window
+ virtual wxBorder GetDefaultBorder() const { return wxBORDER_NONE; }
+
virtual wxBitmap DoGetBitmap(State WXUNUSED(which)) const
{ return wxBitmap(); }
virtual void DoSetBitmap(const wxBitmap& WXUNUSED(bitmap),
{ }
virtual void DoSetBitmapMargins(wxCoord WXUNUSED(x), wxCoord WXUNUSED(y))
{ }
+ virtual void DoSetBitmapPosition(wxDirection WXUNUSED(dir))
+ { }
wxDECLARE_NO_COPY_CLASS(wxButtonBase);
};
// radio boxes
+enum
+{
+ ButtonImagePos_Left,
+ ButtonImagePos_Right,
+ ButtonImagePos_Top,
+ ButtonImagePos_Bottom
+};
+
enum
{
ButtonHAlign_Left,
*m_chkUseHover,
*m_chkUseDisabled;
+ // and an image position choice used if m_chkImage is on
+ wxRadioBox *m_radioImagePos;
+
wxRadioBox *m_radioHAlign,
*m_radioVAlign;
m_chkUseHover =
m_chkUseDisabled = (wxCheckBox *)NULL;
+ m_radioImagePos =
m_radioHAlign =
m_radioVAlign = (wxRadioBox *)NULL;
m_chkFit = CreateCheckBoxAndAddToSizer(sizerLeft, _T("&Fit exactly"));
m_chkDefault = CreateCheckBoxAndAddToSizer(sizerLeft, _T("&Default"));
-#ifndef __WXUNIVERSAL__
- // only wxUniv currently supports buttons with images
- m_chkImage->Disable();
-#endif // !wxUniv
-
sizerLeft->AddSpacer(5);
wxSizer *sizerUseLabels =
- new wxStaticBoxSizer(wxVERTICAL, this, _T("&Use the following labels?"));
+ new wxStaticBoxSizer(wxVERTICAL, this, _T("&Use the following bitmaps?"));
m_chkUseSelected = CreateCheckBoxAndAddToSizer(sizerUseLabels, _T("&Pushed"));
m_chkUseFocused = CreateCheckBoxAndAddToSizer(sizerUseLabels, _T("&Focused"));
m_chkUseHover = CreateCheckBoxAndAddToSizer(sizerUseLabels, _T("&Hover"));
m_chkUseDisabled = CreateCheckBoxAndAddToSizer(sizerUseLabels, _T("&Disabled"));
sizerLeft->Add(sizerUseLabels, wxSizerFlags().Expand().Border());
+ sizerLeft->AddSpacer(10);
+
+ static const wxString dirs[] =
+ {
+ "left", "right", "top", "bottom",
+ };
+ m_radioImagePos = new wxRadioBox(this, wxID_ANY, "Image &position",
+ wxDefaultPosition, wxDefaultSize,
+ WXSIZEOF(dirs), dirs);
+ sizerLeft->Add(m_radioImagePos, 0, wxGROW | wxALL, 5);
sizerLeft->AddSpacer(15);
// should be in sync with enums Button[HV]Align!
m_chkUseHover->SetValue(true);
m_chkUseDisabled->SetValue(true);
+ m_radioImagePos->SetSelection(ButtonImagePos_Left);
m_radioHAlign->SetSelection(ButtonHAlign_Centre);
m_radioVAlign->SetSelection(ButtonVAlign_Centre);
}
m_chkUseHover->Enable(isBitmapButton);
m_chkUseDisabled->Enable(isBitmapButton);
-#ifdef __WXUNIVERSAL__
if ( m_chkImage->GetValue() )
{
- m_button->SetImageLabel(wxArtProvider::GetIcon(wxART_INFORMATION));
+ static const wxDirection positions[] =
+ {
+ wxLEFT, wxRIGHT, wxTOP, wxBOTTOM
+ };
+
+ m_button->SetBitmap(wxArtProvider::GetIcon(wxART_INFORMATION),
+ positions[m_radioImagePos->GetSelection()]);
}
-#endif // wxUniv
if ( m_chkDefault->GetValue() )
{
#include "wx/dcscreen.h"
#include "wx/dcclient.h"
#include "wx/toplevel.h"
+ #include "wx/imaglist.h"
#endif
#include "wx/stockitem.h"
#define TMT_CONTENTMARGINS 3602
#endif
+ // provide the necessary declarations ourselves if they're missing from
+ // headers
#ifndef BCM_SETIMAGELIST
#define BCM_SETIMAGELIST 0x1602
#define BCM_SETTEXTMARGIN 0x1604
+
+ enum
+ {
+ BUTTON_IMAGELIST_ALIGN_LEFT,
+ BUTTON_IMAGELIST_ALIGN_RIGHT,
+ BUTTON_IMAGELIST_ALIGN_TOP,
+ BUTTON_IMAGELIST_ALIGN_BOTTOM
+ };
+
+ struct BUTTON_IMAGELIST
+ {
+ HIMAGELIST himl;
+ RECT margin;
+ UINT uAlign;
+ };
#endif
#endif // wxUSE_UXTHEME
#define DT_HIDEPREFIX 0x00100000
#endif
+// ----------------------------------------------------------------------------
+// button image data
+// ----------------------------------------------------------------------------
+
+// we use different data classes for owner drawn buttons and for themed XP ones
+
+class wxButtonImageData
+{
+public:
+ wxButtonImageData() { }
+
+ virtual wxBitmap GetBitmap(wxButton::State which) const = 0;
+ virtual void SetBitmap(const wxBitmap& bitmap, wxButton::State which) = 0;
+
+ virtual wxSize GetBitmapMargins() const = 0;
+ virtual void SetBitmapMargins(wxCoord x, wxCoord y) = 0;
+
+ virtual bool IsHorizontal() const = 0;
+ virtual void SetBitmapPosition(wxDirection dir) = 0;
+
+private:
+ wxDECLARE_NO_COPY_CLASS(wxButtonImageData);
+};
+
+namespace
+{
+
+class wxODButtonImageData : public wxButtonImageData
+{
+public:
+ wxODButtonImageData() { m_dir = wxLEFT; }
+
+ virtual wxBitmap GetBitmap(wxButton::State which) const
+ {
+ return m_bitmaps[which];
+ }
+
+ virtual void SetBitmap(const wxBitmap& bitmap, wxButton::State which)
+ {
+ m_bitmaps[which] = bitmap;
+ }
+
+ virtual wxSize GetBitmapMargins() const
+ {
+ return m_margin;
+ }
+
+ virtual void SetBitmapMargins(wxCoord x, wxCoord y)
+ {
+ m_margin = wxSize(x, y);
+ }
+
+ virtual bool IsHorizontal() const
+ {
+ return m_dir == wxLEFT || m_dir == wxRIGHT;
+ }
+
+ virtual void SetBitmapPosition(wxDirection dir)
+ {
+ m_dir = dir;
+ }
+
+private:
+ // just store the values passed to us to be able to retrieve them later
+ // from the drawing code
+ wxBitmap m_bitmaps[wxButton::State_Max];
+ wxSize m_margin;
+ wxDirection m_dir;
+
+ wxDECLARE_NO_COPY_CLASS(wxODButtonImageData);
+};
+
+#if wxUSE_UXTHEME
+
+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),
+ m_hwndBtn(GetHwndOf(btn))
+ {
+ m_data.himl = GetHimagelistOf(&m_iml);
+
+ // use default margins
+ m_data.margin.left =
+ m_data.margin.right = btn->GetCharWidth();
+ m_data.margin.top =
+ m_data.margin.bottom = btn->GetCharHeight() / 2;
+
+ // and default alignment
+ m_data.uAlign = BUTTON_IMAGELIST_ALIGN_LEFT;
+ }
+
+ virtual wxBitmap GetBitmap(wxButton::State which) const
+ {
+ return m_iml.GetBitmap(which);
+ }
+
+ 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);
+ }
+
+ UpdateImageInfo();
+ }
+
+ virtual wxSize GetBitmapMargins() const
+ {
+ return wxSize(m_data.margin.left, m_data.margin.top);
+ }
+
+ virtual void SetBitmapMargins(wxCoord x, wxCoord y)
+ {
+ RECT& margin = m_data.margin;
+ margin.left =
+ margin.right = x;
+ margin.top =
+ margin.bottom = y;
+
+ if ( !::SendMessage(m_hwndBtn, BCM_SETTEXTMARGIN, 0, (LPARAM)&margin) )
+ {
+ wxLogDebug("SendMessage(BCM_SETTEXTMARGIN) failed");
+ }
+ }
+
+ virtual bool IsHorizontal() const
+ {
+ return m_data.uAlign == BUTTON_IMAGELIST_ALIGN_LEFT ||
+ m_data.uAlign == BUTTON_IMAGELIST_ALIGN_RIGHT;
+ }
+
+ virtual void SetBitmapPosition(wxDirection dir)
+ {
+ UINT alignNew;
+ switch ( dir )
+ {
+ default:
+ wxFAIL_MSG( "invalid direction" );
+ // fall through
+
+ case wxLEFT:
+ alignNew = BUTTON_IMAGELIST_ALIGN_LEFT;
+ break;
+
+ case wxRIGHT:
+ alignNew = BUTTON_IMAGELIST_ALIGN_RIGHT;
+ break;
+
+ case wxTOP:
+ alignNew = BUTTON_IMAGELIST_ALIGN_TOP;
+ break;
+
+ case wxBOTTOM:
+ alignNew = BUTTON_IMAGELIST_ALIGN_BOTTOM;
+ break;
+ }
+
+ if ( alignNew != m_data.uAlign )
+ {
+ m_data.uAlign = alignNew;
+ UpdateImageInfo();
+ }
+ }
+
+private:
+ void UpdateImageInfo()
+ {
+ if ( !::SendMessage(m_hwndBtn, BCM_SETIMAGELIST, 0, (LPARAM)&m_data) )
+ {
+ wxLogDebug("SendMessage(BCM_SETIMAGELIST) failed");
+ }
+ }
+
+ // we store image list separately to be able to use convenient wxImageList
+ // methods instead of working with raw HIMAGELIST
+ wxImageList m_iml;
+
+ // store the rest of the data in BCM_SETIMAGELIST-friendly form
+ BUTTON_IMAGELIST m_data;
+
+ // the button we're associated with
+ const HWND m_hwndBtn;
+
+
+ wxDECLARE_NO_COPY_CLASS(wxXPButtonImageData);
+};
+
+#endif // wxUSE_UXTHEME
+
+} // anonymous namespace
+
// ----------------------------------------------------------------------------
// macros
// ----------------------------------------------------------------------------
{
UnsetTmpDefault();
}
+
+ delete m_imageData;
}
// ----------------------------------------------------------------------------
wxSize wxButton::DoGetBestSize() const
{
- return wxMSWButton::ComputeBestSize(const_cast<wxButton *>(this));
+ wxSize size = wxMSWButton::ComputeBestSize(const_cast<wxButton *>(this));
+ if ( m_imageData )
+ {
+ const wxSize sizeBmp = m_imageData->GetBitmap(State_Normal).GetSize();
+ if ( m_imageData->IsHorizontal() )
+ {
+ 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;
+ }
+
+ size += 2*m_imageData->GetBitmapMargins();
+
+ CacheBestSize(size);
+ }
+
+ return size;
}
/* static */
return wxControl::MSWWindowProc(nMsg, wParam, lParam);
}
+// ----------------------------------------------------------------------------
+// button images
+// ----------------------------------------------------------------------------
+
+wxBitmap wxButton::DoGetBitmap(State which) const
+{
+ return m_imageData ? m_imageData->GetBitmap(which) : wxBitmap();
+}
+
+void wxButton::DoSetBitmap(const wxBitmap& bitmap, State which)
+{
+ // allocate the image data when the first bitmap is set
+ if ( !m_imageData )
+ {
+#if wxUSE_UXTHEME
+ if ( wxUxThemeEngine::GetIfActive() )
+ m_imageData = new wxXPButtonImageData(this, bitmap.GetSize());
+ else
+#endif // wxUSE_UXTHEME
+ m_imageData = new wxODButtonImageData;
+
+ // if a bitmap was assigned to the bitmap, its best size must be
+ // changed to account for it
+ InvalidateBestSize();
+ }
+
+ m_imageData->SetBitmap(bitmap, which);
+}
+
+void wxButton::DoSetBitmapMargins(wxCoord x, wxCoord y)
+{
+ wxCHECK_RET( m_imageData, "SetBitmap() must be called first" );
+
+ m_imageData->SetBitmapMargins(x, y);
+}
+
+void wxButton::DoSetBitmapPosition(wxDirection dir)
+{
+ wxCHECK_RET( m_imageData, "SetBitmap() must be called first" );
+
+ m_imageData->SetBitmapPosition(dir);
+}
+
// ----------------------------------------------------------------------------
// owner-drawn buttons support
// ----------------------------------------------------------------------------