implement images support for wxButton under XP and later
git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@61054 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
parent
81cb7b5a98
commit
233f10bf15
@ -99,7 +99,7 @@ public:
|
||||
|
||||
// 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
|
||||
@ -130,20 +130,26 @@ public:
|
||||
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),
|
||||
@ -151,6 +157,8 @@ protected:
|
||||
{ }
|
||||
virtual void DoSetBitmapMargins(wxCoord WXUNUSED(x), wxCoord WXUNUSED(y))
|
||||
{ }
|
||||
virtual void DoSetBitmapPosition(wxDirection WXUNUSED(dir))
|
||||
{ }
|
||||
|
||||
|
||||
wxDECLARE_NO_COPY_CLASS(wxButtonBase);
|
||||
|
@ -19,7 +19,7 @@
|
||||
class WXDLLIMPEXP_CORE wxButton : public wxButtonBase
|
||||
{
|
||||
public:
|
||||
wxButton() { }
|
||||
wxButton() { m_imageData = NULL; }
|
||||
wxButton(wxWindow *parent,
|
||||
wxWindowID id,
|
||||
const wxString& label = wxEmptyString,
|
||||
@ -29,6 +29,8 @@ public:
|
||||
const wxValidator& validator = wxDefaultValidator,
|
||||
const wxString& name = wxButtonNameStr)
|
||||
{
|
||||
m_imageData = NULL;
|
||||
|
||||
Create(parent, id, label, pos, size, style, validator, name);
|
||||
}
|
||||
|
||||
@ -78,6 +80,13 @@ protected:
|
||||
// usually overridden base class virtuals
|
||||
virtual wxSize DoGetBestSize() const;
|
||||
|
||||
virtual wxBitmap DoGetBitmap(State which) const;
|
||||
virtual void DoSetBitmap(const wxBitmap& bitmap, State which);
|
||||
virtual void DoSetBitmapMargins(wxCoord x, wxCoord y);
|
||||
virtual void DoSetBitmapPosition(wxDirection dir);
|
||||
|
||||
class wxButtonImageData *m_imageData;
|
||||
|
||||
private:
|
||||
DECLARE_DYNAMIC_CLASS_NO_COPY(wxButton)
|
||||
};
|
||||
|
@ -58,6 +58,14 @@ enum
|
||||
};
|
||||
|
||||
// radio boxes
|
||||
enum
|
||||
{
|
||||
ButtonImagePos_Left,
|
||||
ButtonImagePos_Right,
|
||||
ButtonImagePos_Top,
|
||||
ButtonImagePos_Bottom
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
ButtonHAlign_Left,
|
||||
@ -124,6 +132,9 @@ protected:
|
||||
*m_chkUseHover,
|
||||
*m_chkUseDisabled;
|
||||
|
||||
// and an image position choice used if m_chkImage is on
|
||||
wxRadioBox *m_radioImagePos;
|
||||
|
||||
wxRadioBox *m_radioHAlign,
|
||||
*m_radioVAlign;
|
||||
|
||||
@ -179,6 +190,7 @@ ButtonWidgetsPage::ButtonWidgetsPage(WidgetsBookCtrl *book,
|
||||
m_chkUseHover =
|
||||
m_chkUseDisabled = (wxCheckBox *)NULL;
|
||||
|
||||
m_radioImagePos =
|
||||
m_radioHAlign =
|
||||
m_radioVAlign = (wxRadioBox *)NULL;
|
||||
|
||||
@ -202,21 +214,26 @@ void ButtonWidgetsPage::CreateContent()
|
||||
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!
|
||||
@ -293,6 +310,7 @@ void ButtonWidgetsPage::Reset()
|
||||
m_chkUseHover->SetValue(true);
|
||||
m_chkUseDisabled->SetValue(true);
|
||||
|
||||
m_radioImagePos->SetSelection(ButtonImagePos_Left);
|
||||
m_radioHAlign->SetSelection(ButtonHAlign_Centre);
|
||||
m_radioVAlign->SetSelection(ButtonVAlign_Centre);
|
||||
}
|
||||
@ -385,12 +403,16 @@ void ButtonWidgetsPage::CreateButton()
|
||||
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() )
|
||||
{
|
||||
|
@ -44,4 +44,16 @@ wxWindow *wxButtonBase::SetDefault()
|
||||
return tlw->SetDefaultItem(this);
|
||||
}
|
||||
|
||||
void wxButtonBase::SetBitmapPosition(wxDirection dir)
|
||||
{
|
||||
wxASSERT_MSG( !(dir & ~wxDIRECTION_MASK), "non-direction flag used" );
|
||||
wxASSERT_MSG( !!(dir & wxLEFT) +
|
||||
!!(dir & wxRIGHT) +
|
||||
!!(dir & wxTOP) +
|
||||
!!(dir & wxBOTTOM) == 1,
|
||||
"exactly one direction flag must be set" );
|
||||
|
||||
DoSetBitmapPosition(dir);
|
||||
|
||||
}
|
||||
#endif // wxUSE_BUTTON
|
||||
|
@ -37,6 +37,7 @@
|
||||
#include "wx/dcscreen.h"
|
||||
#include "wx/dcclient.h"
|
||||
#include "wx/toplevel.h"
|
||||
#include "wx/imaglist.h"
|
||||
#endif
|
||||
|
||||
#include "wx/stockitem.h"
|
||||
@ -59,9 +60,26 @@
|
||||
#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
|
||||
|
||||
@ -81,6 +99,213 @@
|
||||
#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
|
||||
// ----------------------------------------------------------------------------
|
||||
@ -259,6 +484,8 @@ wxButton::~wxButton()
|
||||
{
|
||||
UnsetTmpDefault();
|
||||
}
|
||||
|
||||
delete m_imageData;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
@ -310,7 +537,29 @@ void wxButton::SetLabel(const wxString& label)
|
||||
|
||||
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 */
|
||||
@ -590,6 +839,49 @@ WXLRESULT wxButton::MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam)
|
||||
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
|
||||
// ----------------------------------------------------------------------------
|
||||
|
Loading…
Reference in New Issue
Block a user