/////////////////////////////////////////////////////////////////////////////
-// Name: src/mac/carbon/bmpbuttn.cpp
+// Name: src/osx/carbon/bmpbuttn.cpp
// Purpose: wxBitmapButton
// Author: Stefan Csomor
// Modified by:
#include "wx/dcmemory.h"
#endif
-IMPLEMENT_DYNAMIC_CLASS(wxBitmapButton, wxButton)
+#include "wx/osx/private.h"
-#include "wx/mac/uma.h"
-
-//---------------------------------------------------------------------------
-// Helper functions
-
-static wxBitmap wxMakeStdSizeBitmap(const wxBitmap& bitmap)
+namespace
{
- // in Mac OS X the icon controls (which are used for borderless bitmap
- // buttons) can have only one of the few standard sizes and if they
- // don't, the OS rescales them automatically resulting in really ugly
- // images, so centre the image in a square of standard size instead
-
- // the supported sizes, sorted in decreasng order
- static const int stdSizes[] = { 128, 48, 32, 16, 0 };
- const int width = bitmap.GetWidth();
- const int height = bitmap.GetHeight();
-
- wxBitmap newBmp(bitmap);
-
- int n;
- for ( n = 0; n < (int)WXSIZEOF(stdSizes); n++ )
+// define a derived class to override SetBitmap() and also to provide
+// InitButtonContentInfo() helper used by CreateBitmapButton()
+class wxMacBitmapButton : public wxMacControl
+{
+public:
+ wxMacBitmapButton(wxWindowMac* peer, const wxBitmap& bitmap, int style)
+ : wxMacControl(peer)
{
- const int sizeStd = stdSizes[n];
- if ( width > sizeStd || height > sizeStd )
- {
- // it will become -1 if the bitmap is larger than the biggest
- // supported size, this is intentional
- n--;
-
- break;
- }
+ // decide what kind of contents the button will have: we want to use an
+ // icon for buttons with wxBORDER_NONE style as bevel buttons always do
+ // have a border but icons are limited to a few standard sizes only and
+ // are resized by the system with extremely ugly results if they don't
+ // fit (in the past we also tried being smart and pasting a bitmap
+ // instead of a larger square icon to avoid resizing but this resulted
+ // in buttons having different size than specified by wx API and
+ // breaking the layouts and still didn't look good so we don't even try
+ // to do this any more)
+ m_isIcon = (style & wxBORDER_NONE) &&
+ bitmap.IsOk() && IsOfStandardSize(bitmap);
}
- if ( n != -1 )
+ virtual void SetBitmap(const wxBitmap& bitmap)
{
- const int sizeStd = stdSizes[n];
- if ( width != sizeStd || height != sizeStd )
- {
- wxASSERT_MSG( width <= sizeStd && height <= sizeStd,
- _T("bitmap shouldn't be cropped") );
-
- wxImage square_image = bitmap.ConvertToImage();
- newBmp = square_image.Size
- (
- wxSize(sizeStd, sizeStd),
- wxPoint((sizeStd - width)/2, (sizeStd-height)/2)
- );
- }
+ // unfortunately we can't avoid the ugly resizing problem mentioned
+ // above if a bitmap of supported size was used initially but was
+ // replaced with another one later as the control was already created
+ // as an icon control (although maybe we ought to recreate it?)
+ ControlButtonContentInfo info;
+ InitButtonContentInfo(info, bitmap);
+
+ if ( info.contentType == kControlContentIconRef )
+ SetData(kControlIconPart, kControlIconContentTag, info);
+ else if ( info.contentType != kControlNoContent )
+ SetData(kControlButtonPart, kControlBevelButtonContentTag, info);
+
+ wxMacReleaseBitmapButton(&info);
}
- //else: let the system rescale the bitmap
-
- return newBmp;
-}
-
-//---------------------------------------------------------------------------
-
-bool wxBitmapButton::Create( wxWindow *parent,
- wxWindowID id, const wxBitmap& bitmap,
- const wxPoint& pos,
- const wxSize& size,
- long style,
- const wxValidator& validator,
- const wxString& name )
-{
- m_macIsUserPane = false;
-
- // since bitmapbuttonbase is subclass of button calling wxBitmapButtonBase::Create
- // essentially creates an additional button
- if ( !wxControl::Create( parent, id, pos, size, style, validator, name ) )
- return false;
- if ( style & wxBU_AUTODRAW )
+ void InitButtonContentInfo(ControlButtonContentInfo& info,
+ const wxBitmap& bitmap)
{
- m_marginX =
- m_marginY = wxDEFAULT_BUTTON_MARGIN;
+ wxMacCreateBitmapButton(&info, bitmap,
+ m_isIcon ? kControlContentIconRef : 0);
}
- else
- {
- m_marginX =
- m_marginY = 0;
- }
-
- OSStatus err = noErr;
- ControlButtonContentInfo info;
-
- Rect bounds = wxMacGetBoundsForControl( this, pos, size );
- m_peer = new wxMacControl( this );
-
- if ( bitmap.Ok() && HasFlag(wxBORDER_NONE) )
- m_bmpNormal = wxMakeStdSizeBitmap(bitmap);
- else
- m_bmpNormal = bitmap;
-
- if ( HasFlag( wxBORDER_NONE ) )
+private:
+ // helper function: returns true if the given bitmap is of one of standard
+ // sizes supported by OS X icons
+ static bool IsOfStandardSize(const wxBitmap& bmp)
{
- // contrary to the docs this control only works with iconrefs
- wxMacCreateBitmapButton( &info, m_bmpNormal, kControlContentIconRef );
- err = CreateIconControl(
- MAC_WXHWND(parent->MacGetTopLevelWindowRef()),
- &bounds, &info, false, m_peer->GetControlRefAddr() );
- }
- else
- {
- wxMacCreateBitmapButton( &info, m_bmpNormal );
- err = CreateBevelButtonControl(
- MAC_WXHWND(parent->MacGetTopLevelWindowRef()), &bounds, CFSTR(""),
- ((style & wxBU_AUTODRAW) ? kControlBevelButtonSmallBevel : kControlBevelButtonNormalBevel ),
- kControlBehaviorOffsetContents, &info, 0, 0, 0, m_peer->GetControlRefAddr() );
+ const int w = bmp.GetWidth();
+
+ return bmp.GetHeight() == w &&
+ (w == 128 || w == 48 || w == 32 || w == 16);
}
- verify_noerr( err );
- wxMacReleaseBitmapButton( &info );
- wxASSERT_MSG( m_peer != NULL && m_peer->Ok(), wxT("No valid native Mac control") );
+ // true if this is an icon control, false if it's a bevel button
+ bool m_isIcon;
- MacPostControlCreate( pos, size );
+ wxDECLARE_NO_COPY_CLASS(wxMacBitmapButton);
+};
- return true;
-}
+} // anonymous namespace
-void wxBitmapButton::SetBitmapLabel( const wxBitmap& bitmap )
+wxWidgetImplType* wxWidgetImpl::CreateBitmapButton( wxWindowMac* wxpeer,
+ wxWindowMac* parent,
+ wxWindowID WXUNUSED(id),
+ const wxBitmap& bitmap,
+ const wxPoint& pos,
+ const wxSize& size,
+ long style,
+ long WXUNUSED(extraStyle))
{
- if ( HasFlag( wxBORDER_NONE ) )
- m_bmpNormal = wxMakeStdSizeBitmap(bitmap);
- else
- m_bmpNormal = bitmap;
-
- InvalidateBestSize();
+ wxMacBitmapButton* peer = new wxMacBitmapButton(wxpeer, bitmap, style);
+
+ OSStatus err;
+ WXWindow macParent = MAC_WXHWND(parent->MacGetTopLevelWindowRef());
+ Rect bounds = wxMacGetBoundsForControl( wxpeer, pos, size );
ControlButtonContentInfo info;
+ peer->InitButtonContentInfo(info, bitmap);
- if ( HasFlag( wxBORDER_NONE ) )
- {
- wxMacCreateBitmapButton( &info, m_bmpNormal, kControlContentIconRef );
- if ( info.contentType != kControlNoContent )
- m_peer->SetData( kControlIconPart, kControlIconContentTag, info );
- }
- else
+ if ( info.contentType == kControlContentIconRef )
{
- wxMacCreateBitmapButton( &info, m_bmpNormal );
- if ( info.contentType != kControlNoContent )
- m_peer->SetData( kControlButtonPart, kControlBevelButtonContentTag, info );
+ err = CreateIconControl
+ (
+ macParent,
+ &bounds,
+ &info,
+ false,
+ peer->GetControlRefAddr()
+ );
}
-
- wxMacReleaseBitmapButton( &info );
-}
-
-wxSize wxBitmapButton::DoGetBestSize() const
-{
- wxSize best;
-
- best.x = 2 * m_marginX;
- best.y = 2 * m_marginY;
- if ( m_bmpNormal.Ok() )
+ else // normal bevel button
{
- best.x += m_bmpNormal.GetWidth();
- best.y += m_bmpNormal.GetHeight();
+ err = CreateBevelButtonControl
+ (
+ macParent,
+ &bounds,
+ CFSTR(""),
+ style & wxBU_AUTODRAW ? kControlBevelButtonSmallBevel
+ : kControlBevelButtonNormalBevel,
+ kControlBehaviorOffsetContents,
+ &info,
+ 0, // menu id (no associated menu)
+ 0, // menu behaviour (unused)
+ 0, // menu placement (unused too)
+ peer->GetControlRefAddr()
+ );
}
- return best;
+ verify_noerr( err );
+
+ wxMacReleaseBitmapButton( &info );
+ return peer;
}
-#endif
+#endif // wxUSE_BMPBUTTON