Add wxStaticBitmap::SetScaleMode() to control bitmap display size

This allows a bitmap to scale with the size of the wxStaticBitmap control.
Scaling can be controlled to fill the control with or without changing the
bitmaps aspect ratio.
This commit is contained in:
Tobias Taschner 2016-01-19 18:52:50 +01:00 committed by Vadim Zeitlin
parent 9c95b398c8
commit 58c7e6d54f
5 changed files with 157 additions and 3 deletions

View File

@ -56,6 +56,13 @@ public:
wxIcon GetIcon() const wxOVERRIDE { return (const wxIcon &)m_bitmap; }
#endif
virtual void SetScaleMode(ScaleMode scaleMode) wxOVERRIDE
{
m_scaleMode = scaleMode;
Refresh();
}
virtual ScaleMode GetScaleMode() const wxOVERRIDE { return m_scaleMode; }
private:
wxSize GetBitmapSize()
@ -67,6 +74,7 @@ private:
void OnPaint(wxPaintEvent& event);
wxBitmap m_bitmap;
ScaleMode m_scaleMode;
wxDECLARE_DYNAMIC_CLASS(wxGenericStaticBitmap);
};

View File

@ -25,6 +25,14 @@ extern WXDLLIMPEXP_DATA_CORE(const char) wxStaticBitmapNameStr[];
class WXDLLIMPEXP_CORE wxStaticBitmapBase : public wxControl
{
public:
enum ScaleMode
{
Scale_None,
Scale_Fill,
Scale_AspectFit,
Scale_AspectFill
};
wxStaticBitmapBase() { }
virtual ~wxStaticBitmapBase();
@ -38,6 +46,8 @@ public:
// should)
return wxIcon();
}
virtual void SetScaleMode(ScaleMode WXUNUSED(scaleMode)) { }
virtual ScaleMode GetScaleMode() const { return Scale_None; }
// overridden base class virtuals
virtual bool AcceptsFocus() const wxOVERRIDE { return false; }

View File

@ -19,7 +19,8 @@
same as the size of the image displayed in it, as happens by default if
it's not resized explicitly. Otherwise, behaviour depends on the
platform: under MSW, the bitmap is drawn centred inside the control, while
elsewhere it is drawn at the origin of the control.
elsewhere it is drawn at the origin of the control. You can use
SetScaleMode() to control how the image is scaled inside the control.
@library{wxcore}
@category{ctrl}
@ -30,6 +31,38 @@
class wxStaticBitmap : public wxControl
{
public:
/**
Specify how the bitmap should be scaled in the control.
@see SetScaleMode(), GetScaleMode()
*/
enum ScaleMode
{
/**
The bitmap is displayed in original size. Portions larger then the
control will be cut off.
*/
Scale_None,
/**
Scale the bitmap to fit the size of the control by changing the
aspect ratio of the bitmap if necessary.
*/
Scale_Fill,
/**
Scale the bitmap to fit the size of the control by maintaining the
aspect ratio. Any remaining area of the control will use the background.
*/
Scale_AspectFit,
/**
Scale the bitmap to fill the size of the control. Some portion of
the bitmap may be clipped to fill the control.
*/
Scale_AspectFill
};
/**
Default constructor
*/
@ -105,5 +138,31 @@ public:
The new icon.
*/
virtual void SetIcon(const wxIcon& label);
/**
Sets the scale mode.
@param scaleMode
Controls how the bitmap is scaled inside the control.
@note Currently only the generic implementation supports all scaling modes.
You may use generic implementation wxGenericStaticBitmap declared in
\<wx/generic/statbmpg.h\> in all ports.
@see GetScaleMode()
@since 3.1.0
*/
virtual void SetScaleMode(ScaleMode scaleMode);
/**
Returns the scale mode currently used in the control.
@see SetScaleMode()
@since 3.1.0
*/
virtual ScaleMode GetScaleMode() const;
};

View File

@ -67,6 +67,7 @@ private:
wxStaticBitmapBase *m_statbmp;
wxFilePickerCtrl *m_filepicker;
wxRadioBox *m_radio;
wxRadioBox *m_scaleRadio;
wxStaticBoxSizer *m_sbsizer;
DECLARE_WIDGETS_PAGE(StatBmpWidgetsPage)
@ -82,6 +83,10 @@ void StatBmpWidgetsPage::CreateContent()
m_radio = new wxRadioBox(this, wxID_ANY, "implementation",
wxDefaultPosition, wxDefaultSize,
WXSIZEOF(choices), choices);
static const wxString scaleChoices[] = { "None", "Fill", "Aspect Fit", "Aspect Fill" };
m_scaleRadio = new wxRadioBox(this, wxID_ANY, "Scale Mode",
wxDefaultPosition, wxDefaultSize,
WXSIZEOF(scaleChoices), scaleChoices);
wxString testImage;
#if wxUSE_LIBPNG
@ -95,6 +100,7 @@ void StatBmpWidgetsPage::CreateContent()
wxSizer *leftsizer = new wxBoxSizer(wxVERTICAL);
leftsizer->Add(m_radio, wxSizerFlags().Expand().Border());
leftsizer->Add(m_scaleRadio, wxSizerFlags().Expand().Border());
leftsizer->Add(m_filepicker, wxSizerFlags().Expand().Border());
wxSizer *sizer = new wxBoxSizer(wxHORIZONTAL);
sizer->Add(leftsizer, wxSizerFlags().Border());
@ -130,6 +136,22 @@ void StatBmpWidgetsPage::RecreateWidget()
m_statbmp = new wxStaticBitmap(this, wxID_ANY, wxBitmap(image));
else
m_statbmp = new wxGenericStaticBitmap(this, wxID_ANY, wxBitmap(image));
wxStaticBitmapBase::ScaleMode scaleMode = (wxStaticBitmapBase::ScaleMode) m_scaleRadio->GetSelection();
m_statbmp->SetScaleMode(scaleMode);
if ( m_statbmp->GetScaleMode() != scaleMode )
wxLogError("Scale mode not supported by current implementation");
wxSizerItem* sbsizerItem = GetSizer()->GetItem(m_sbsizer);
if ( scaleMode == wxStaticBitmapBase::Scale_None )
{
sbsizerItem->SetProportion(0);
sbsizerItem->SetFlag(wxCENTER);
}
else
{
sbsizerItem->SetProportion(1);
sbsizerItem->SetFlag(wxEXPAND);
}
m_sbsizer->Add(m_statbmp, wxSizerFlags(1).Expand());
GetSizer()->Layout();
m_statbmp->Connect(wxEVT_LEFT_DOWN,

View File

@ -17,6 +17,14 @@
#include "wx/generic/statbmpg.h"
#if wxUSE_GRAPHICS_CONTEXT
#include "wx/graphics.h"
#include "wx/scopedptr.h"
#else
#include "wx/image.h"
#include "wx/math.h"
#endif
bool wxGenericStaticBitmap::Create(wxWindow *parent, wxWindowID id,
const wxBitmap& bitmap,
const wxPoint& pos, const wxSize& size,
@ -25,6 +33,7 @@ bool wxGenericStaticBitmap::Create(wxWindow *parent, wxWindowID id,
if (! wxControl::Create(parent, id, pos, size, style,
wxDefaultValidator, name))
return false;
m_scaleMode = Scale_None;
SetBitmap(bitmap);
Connect(wxEVT_PAINT, wxPaintEventHandler(wxGenericStaticBitmap::OnPaint));
return true;
@ -32,9 +41,55 @@ bool wxGenericStaticBitmap::Create(wxWindow *parent, wxWindowID id,
void wxGenericStaticBitmap::OnPaint(wxPaintEvent& WXUNUSED(event))
{
if ( !m_bitmap.IsOk() )
return;
wxPaintDC dc(this);
if (m_bitmap.IsOk())
const wxSize drawSize = GetClientSize();
const wxSize bmpSize = m_bitmap.GetSize();
wxDouble w = 0;
wxDouble h = 0;
switch ( m_scaleMode )
{
case Scale_None:
dc.DrawBitmap(m_bitmap, 0, 0, true);
return;
case Scale_Fill:
w = drawSize.x;
h = drawSize.y;
break;
case Scale_AspectFill:
case Scale_AspectFit:
{
wxDouble scaleFactor;
wxDouble scaleX = (wxDouble)drawSize.x / (wxDouble)bmpSize.x;
wxDouble scaleY = (wxDouble)drawSize.y / (wxDouble)bmpSize.y;
if ( ( m_scaleMode == Scale_AspectFit && scaleY < scaleX ) ||
( m_scaleMode == Scale_AspectFill && scaleY > scaleX ) )
scaleFactor = scaleY;
else
scaleFactor = scaleX;
w = bmpSize.x * scaleFactor;
h = bmpSize.y * scaleFactor;
break;
}
}
wxASSERT_MSG(w, wxS("Unknown scale mode"));
wxDouble x = (drawSize.x - w) / 2;
wxDouble y = (drawSize.y - h) / 2;
#if wxUSE_GRAPHICS_CONTEXT
wxScopedPtr<wxGraphicsContext> const
gc(wxGraphicsRenderer::GetDefaultRenderer()->CreateContext(dc));
gc->DrawBitmap(m_bitmap, x, y, w, h);
#else
wxImage img = m_bitmap.ConvertToImage();
img.Rescale(wxRound(w), wxRound(h), wxIMAGE_QUALITY_HIGH);
dc.DrawBitmap(wxBitmap(img), wxRound(x), wxRound(y), true);
#endif
}
// under OSX_cocoa is a define, avoid duplicate info