diff --git a/include/wx/generic/statbmpg.h b/include/wx/generic/statbmpg.h index 71c1812785..e915473420 100644 --- a/include/wx/generic/statbmpg.h +++ b/include/wx/generic/statbmpg.h @@ -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); }; diff --git a/include/wx/statbmp.h b/include/wx/statbmp.h index c51c19086c..ea888cd501 100644 --- a/include/wx/statbmp.h +++ b/include/wx/statbmp.h @@ -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; } diff --git a/interface/wx/statbmp.h b/interface/wx/statbmp.h index 57054fa890..06bfce85b2 100644 --- a/interface/wx/statbmp.h +++ b/interface/wx/statbmp.h @@ -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 + \ 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; + }; diff --git a/samples/widgets/statbmp.cpp b/samples/widgets/statbmp.cpp index d0d834dc24..a0954e6cb1 100644 --- a/samples/widgets/statbmp.cpp +++ b/samples/widgets/statbmp.cpp @@ -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, diff --git a/src/generic/statbmpg.cpp b/src/generic/statbmpg.cpp index e219d79b9c..285c86d798 100644 --- a/src/generic/statbmpg.cpp +++ b/src/generic/statbmpg.cpp @@ -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()) - dc.DrawBitmap(m_bitmap, 0, 0, true); + 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 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