diff --git a/include/wx/osx/bitmap.h b/include/wx/osx/bitmap.h index 34137f0a4c..d1388a85fb 100644 --- a/include/wx/osx/bitmap.h +++ b/include/wx/osx/bitmap.h @@ -126,6 +126,11 @@ public: // Convert from wxIcon wxBitmap(const wxIcon& icon) { CopyFromIcon(icon); } +#if wxOSX_USE_COCOA + // Convert from wxCursor + wxBitmap(const wxCursor &cursor); +#endif + virtual ~wxBitmap() {} wxImage ConvertToImage() const wxOVERRIDE; diff --git a/include/wx/osx/cocoa/private.h b/include/wx/osx/cocoa/private.h index 08921a8048..eafd4ab3a3 100644 --- a/include/wx/osx/cocoa/private.h +++ b/include/wx/osx/cocoa/private.h @@ -45,6 +45,7 @@ void WXDLLIMPEXP_CORE wxOSXSetImageSize(WX_NSImage image, CGFloat width, CGFloat wxBitmap WXDLLIMPEXP_CORE wxOSXCreateSystemBitmap(const wxString& id, const wxString &client, const wxSize& size); WXWindow WXDLLIMPEXP_CORE wxOSXGetMainWindow(); WXWindow WXDLLIMPEXP_CORE wxOSXGetKeyWindow(); +WXImage WXDLLIMPEXP_CORE wxOSXGetNSImageFromNSCursor(const WXHCURSOR cursor); class WXDLLIMPEXP_FWD_CORE wxDialog; diff --git a/interface/wx/bitmap.h b/interface/wx/bitmap.h index d4922fe3ef..f119444e05 100644 --- a/interface/wx/bitmap.h +++ b/interface/wx/bitmap.h @@ -359,9 +359,6 @@ public: This can be useful to display a cursor as it cannot be drawn directly on a window. - This constructor only exists in wxMSW and wxGTK (where it is - implemented for GTK+ 2.8 or later) only. - @param cursor A valid wxCursor. @since 3.1.0 diff --git a/src/osx/carbon/utilscocoa.mm b/src/osx/carbon/utilscocoa.mm index 9a7c2ceb22..7e27bb21ac 100644 --- a/src/osx/carbon/utilscocoa.mm +++ b/src/osx/carbon/utilscocoa.mm @@ -577,6 +577,11 @@ WX_NSCursor wxMacCocoaCreateStockCursor( int cursor_type ) return cursor; } +WXImage WXDLLIMPEXP_CORE wxOSXGetNSImageFromNSCursor(const WXHCURSOR cursor) +{ + return [(NSCursor *)cursor image]; +} + // C-based style wrapper routines around NSCursor WX_NSCursor wxMacCocoaCreateCursorFromCGImage( CGImageRef cgImageRef, float hotSpotX, float hotSpotY ) { diff --git a/src/osx/core/bitmap.cpp b/src/osx/core/bitmap.cpp index b875ee34f5..cb9f2163e3 100644 --- a/src/osx/core/bitmap.cpp +++ b/src/osx/core/bitmap.cpp @@ -919,6 +919,13 @@ wxBitmap::wxBitmap(WXImage image) (void)Create(image); } +#if wxOSX_USE_COCOA +wxBitmap::wxBitmap(const wxCursor &cursor) +{ + m_refData = new wxBitmapRefData( wxOSXGetNSImageFromNSCursor( cursor.GetHCURSOR() ) ); +} +#endif + bool wxBitmap::Create(WXImage image) { UnRef(); diff --git a/tests/image/image.cpp b/tests/image/image.cpp index 838cb9a655..65225f55d9 100644 --- a/tests/image/image.cpp +++ b/tests/image/image.cpp @@ -20,6 +20,7 @@ #endif // WX_PRECOMP #include "wx/anidecod.h" // wxImageArray +#include "wx/bitmap.h" #include "wx/palette.h" #include "wx/url.h" #include "wx/log.h" @@ -31,6 +32,18 @@ #include "testimage.h" + +#define CHECK_EQUAL_COLOUR_RGB(c1, c2) \ + CHECK( (int)c1.Red() == (int)c2.Red() ); \ + CHECK( (int)c1.Green() == (int)c2.Green() ); \ + CHECK( (int)c1.Blue() == (int)c2.Blue() ) + +#define CHECK_EQUAL_COLOUR_RGBA(c1, c2) \ + CHECK( (int)c1.Red() == (int)c2.Red() ); \ + CHECK( (int)c1.Green() == (int)c2.Green() ); \ + CHECK( (int)c1.Blue() == (int)c2.Blue() ); \ + CHECK( (int)c1.Alpha() == (int)c2.Alpha() ) + struct testData { const char* file; wxBitmapType type; @@ -82,6 +95,7 @@ private: CPPUNIT_TEST( DibPadding ); CPPUNIT_TEST( BMPFlippingAndRLECompression ); CPPUNIT_TEST( ScaleCompare ); + CPPUNIT_TEST( CreateBitmapFromCursor ); CPPUNIT_TEST_SUITE_END(); void LoadFromSocketStream(); @@ -102,6 +116,7 @@ private: void DibPadding(); void BMPFlippingAndRLECompression(); void ScaleCompare(); + void CreateBitmapFromCursor(); wxDECLARE_NO_COPY_CLASS(ImageTestCase); }; @@ -1451,6 +1466,58 @@ void ImageTestCase::ScaleCompare() "image/cross_nearest_neighb_256x256.png"); } +void ImageTestCase::CreateBitmapFromCursor() +{ +#if !defined __WXOSX_IPHONE__ && !defined __WXDFB__ && !defined __WXMOTIF__ && !defined __WXX11__ + + wxImage image("image/wx.png"); + wxCursor cursor(image); + wxBitmap bitmap(cursor); + +#if defined(__WXGTK__) + // cursor to bitmap could fail depending on windowing system and cursor (gdk-cursor-get-image) + if ( !bitmap.IsOk() ) + return; +#endif + + wxImage result = bitmap.ConvertToImage(); + + // on Windows the cursor is always scaled to 32x32px (96 DPI) + // on macOS the resulting bitmap size depends on the DPI + if ( image.GetSize() == result.GetSize() ) + { + CHECK_THAT(image, RGBASimilarTo(result, 2)); + } + else + { + wxVector coords; + coords.push_back(wxPoint(14, 10)); // blue square + coords.push_back(wxPoint(8, 22)); // red square + coords.push_back(wxPoint(26, 18)); // yellow square + coords.push_back(wxPoint(25, 5)); // empty / tranparent + + for ( size_t i = 0; i < coords.size(); ++i ) + { + wxPoint const& p1 = coords[i]; + wxPoint p2 = wxPoint(p1.x * (result.GetWidth() / (double)image.GetWidth()), p1.y * (result.GetHeight() / (double)image.GetHeight())); + +#if defined(__WXMSW__) + // when the cursor / result image is larger than the source image, the original image is centered in the result image + if ( result.GetWidth() > image.GetWidth() ) + p2.x = (result.GetWidth() / 2) + (p1.x - (image.GetWidth() / 2)); + if ( result.GetHeight() > image.GetHeight() ) + p2.y = (result.GetHeight() / 2) + (p1.y - (image.GetHeight() / 2)); +#endif + + wxColour cSrc(image.GetRed(p1.x, p1.y), image.GetGreen(p1.x, p1.y), image.GetBlue(p1.x, p1.y), image.GetAlpha(p1.x, p1.y)); + wxColour cRes(result.GetRed(p2.x, p2.y), result.GetGreen(p2.x, p2.y), result.GetBlue(p2.x, p2.y), result.GetAlpha(p2.x, p2.y)); + + CHECK_EQUAL_COLOUR_RGBA(cRes, cSrc); + } + } +#endif +} + #endif //wxUSE_IMAGE TEST_CASE("wxImage::Paste", "[image][paste]") @@ -1970,17 +2037,6 @@ TEST_CASE("wxImage::Clipboard", "[image][clipboard]") #endif // wxUSE_CLIPBOARD && wxUSE_DATAOBJ } -#define CHECK_EQUAL_COLOUR_RGB(c1, c2) \ - CHECK( (int)c1.Red() == (int)c2.Red() ); \ - CHECK( (int)c1.Green() == (int)c2.Green() ); \ - CHECK( (int)c1.Blue() == (int)c2.Blue() ) - -#define CHECK_EQUAL_COLOUR_RGBA(c1, c2) \ - CHECK( (int)c1.Red() == (int)c2.Red() ); \ - CHECK( (int)c1.Green() == (int)c2.Green() ); \ - CHECK( (int)c1.Blue() == (int)c2.Blue() ); \ - CHECK( (int)c1.Alpha() == (int)c2.Alpha() ) - TEST_CASE("wxImage::InitAlpha", "[image][initalpha]") { const wxColour maskCol(*wxRED); diff --git a/tests/testimage.h b/tests/testimage.h index cb2722db5a..f27f61ac37 100644 --- a/tests/testimage.h +++ b/tests/testimage.h @@ -175,6 +175,11 @@ inline ImageRGBMatcher RGBSimilarTo(const wxImage& image, int tolerance) return ImageRGBMatcher(image, tolerance, false); } +inline ImageRGBMatcher RGBASimilarTo(const wxImage& image, int tolerance) +{ + return ImageRGBMatcher(image, tolerance, true); +} + class ImageAlphaMatcher : public Catch::MatcherBase { public: