+namespace
+{
+
+// the gap between button edge and the interior area used by Windows for the
+// standard buttons
+const int OD_BUTTON_MARGIN = 4;
+
+class wxODButtonImageData : public wxButtonImageData
+{
+public:
+ wxODButtonImageData(wxButton *btn, const wxBitmap& bitmap)
+ {
+ SetBitmap(bitmap, wxButton::State_Normal);
+ SetBitmap(bitmap.ConvertToDisabled(), wxButton::State_Disabled);
+
+ m_dir = wxLEFT;
+
+ // we use margins when we have both bitmap and text, but when we have
+ // only the bitmap it should take up the entire button area
+ if ( btn->ShowsLabel() )
+ {
+ m_margin.x = btn->GetCharWidth();
+ m_margin.y = btn->GetCharHeight() / 2;
+ }
+ }
+
+ 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 wxDirection GetBitmapPosition() const
+ {
+ return m_dir;
+ }
+
+ 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
+
+// somehow the margin is one pixel greater than the value returned by
+// GetThemeMargins() call
+const int XP_BUTTON_EXTRA_MARGIN = 1;
+
+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 wxBitmap& bitmap)
+ : m_iml(bitmap.GetWidth(), bitmap.GetHeight(), true /* use mask */,
+ wxButton::State_Max),
+ m_hwndBtn(GetHwndOf(btn))
+ {
+ // initialize all bitmaps except for the disabled one to normal state
+ for ( int n = 0; n < wxButton::State_Max; n++ )
+ {
+ m_iml.Add(n == wxButton::State_Disabled ? bitmap.ConvertToDisabled()
+ : bitmap);
+ }
+
+ m_data.himl = GetHimagelistOf(&m_iml);
+
+ // no margins by default
+ m_data.margin.left =
+ m_data.margin.right =
+ m_data.margin.top =
+ m_data.margin.bottom = 0;
+
+ // use default alignment
+ m_data.uAlign = BUTTON_IMAGELIST_ALIGN_LEFT;
+
+ UpdateImageInfo();
+ }
+
+ virtual wxBitmap GetBitmap(wxButton::State which) const
+ {
+ return m_iml.GetBitmap(which);
+ }
+
+ virtual void SetBitmap(const wxBitmap& bitmap, wxButton::State which)
+ {
+ 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 wxDirection GetBitmapPosition() const
+ {
+ switch ( m_data.uAlign )
+ {
+ default:
+ wxFAIL_MSG( "invalid image alignment" );
+ // fall through
+
+ case BUTTON_IMAGELIST_ALIGN_LEFT:
+ return wxLEFT;
+
+ case BUTTON_IMAGELIST_ALIGN_RIGHT:
+ return wxRIGHT;
+
+ case BUTTON_IMAGELIST_ALIGN_TOP:
+ return wxTOP;
+
+ case BUTTON_IMAGELIST_ALIGN_BOTTOM:
+ return wxBOTTOM;
+ }
+ }
+
+ 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;