From b737ad10dec946cd7d5e38c43c666e8efe89f0ae Mon Sep 17 00:00:00 2001
From: Robert Roebling <robert@roebling.de>
Date: Fri, 4 Mar 2005 18:33:57 +0000
Subject: [PATCH]   Applied John L's patches for curson scaling, image resizing
     without scaling and the art provider resize bitmap patch.     I'll look
 into adapting the generic file dialog to it.

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@32598 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
---
 docs/latex/wx/artprov.tex  |  6 +++
 docs/latex/wx/cursor.tex   |  4 +-
 docs/latex/wx/image.tex    | 55 +++++++++++++++++++++-
 docs/latex/wx/rect.tex     |  8 ++++
 include/wx/artprov.h       | 10 ++++
 include/wx/gdicmn.h        |  2 +
 include/wx/image.h         | 17 ++++++-
 src/common/artprov.cpp     | 60 +++++++++++++++++++++---
 src/common/image.cpp       | 93 ++++++++++++++++++++++++++++++++++++++
 src/gtk/artgtk.cpp         |  2 +-
 src/gtk1/artgtk.cpp        |  2 +-
 src/mac/carbon/cursor.cpp  | 40 ++++++++++++----
 src/mac/classic/cursor.cpp | 41 ++++++++++++-----
 src/msw/cursor.cpp         | 38 ++++++++++++----
 14 files changed, 334 insertions(+), 44 deletions(-)

diff --git a/docs/latex/wx/artprov.tex b/docs/latex/wx/artprov.tex
index 5ed81edb2f..d0b0fde2b6 100644
--- a/docs/latex/wx/artprov.tex
+++ b/docs/latex/wx/artprov.tex
@@ -176,6 +176,12 @@ The bitmap if one of registered providers recognizes the ID or wxNullBitmap othe
 Same as \helpref{wxArtProvider::GetBitmap}{wxartprovidergetbitmap}, but
 return a wxIcon object (or wxNullIcon on failure).
 
+\func{static wxSize}{GetSize}{\param{const wxArtClient\& }{client}, \param{bool }{platform_default = false}}
+
+Returns the default size for the given art {\it client} by either using the topmost 
+wxArtProvider or if {\it platform_default} is \true then return a suitable default size for 
+{\it client} depending on the current platform.
+
 \membersection{wxArtProvider::PopProvider}\label{wxartproviderctor}
 
 \func{static bool}{PopProvider}{\void}
diff --git a/docs/latex/wx/cursor.tex b/docs/latex/wx/cursor.tex
index 1992f48e3a..3f3d1a5d24 100644
--- a/docs/latex/wx/cursor.tex
+++ b/docs/latex/wx/cursor.tex
@@ -77,10 +77,10 @@ Constructs a cursor using a cursor identifier.
 Constructs a cursor from a wxImage. The cursor is monochrome, colors with the RGB elements all greater
 than 127 will be foreground, colors less than this background. The mask (if any) will be used as transparent.
 
-In MSW the foreground will be white and the background black. The cursor is resized to 32x32
+In MSW the foreground will be white and the background black. If the cursor is larger than 32x32 it is resized.
 In GTK, the two most frequent colors will be used for foreground and background. The cursor will be displayed
 at the size of the image.
-On MacOS the cursor is resized to 16x16 and currently only shown as black/white (mask respected).
+On MacOS if the cursor is larger than 16x16 it is resized and currently only shown as black/white (mask respected).
 
 \func{}{wxCursor}{\param{const wxCursor\&}{ cursor}}
 
diff --git a/docs/latex/wx/image.tex b/docs/latex/wx/image.tex
index c3169fae76..379ce7fb72 100644
--- a/docs/latex/wx/image.tex
+++ b/docs/latex/wx/image.tex
@@ -545,6 +545,14 @@ Gets the green value of the mask colour.
 Gets the red value of the mask colour.
 
 
+\membersection{wxImage::GetOrFindMaskColour}\label{wximagegetgetorsetmaskcolour}
+
+\constfunc{bool}{GetOrFindMaskColour}{\param{unsigned char}{ *r}, \param{unsigned char}{ *g}, \param{unsigned char}{ *b}}
+
+Get the current mask colour or find a suitable unused colour that could be 
+used as a mask colour. Returns {\tt true} if the image currently has a mask.
+
+
 \membersection{wxImage::GetPalette}\label{wximagegetpalette}
 
 \constfunc{const wxPalette\&}{GetPalette}{\void}
@@ -831,8 +839,8 @@ Replaces the colour specified by {\it r1,g1,b1} by the colour {\it r2,g2,b2}.
 
 \func{wxImage \&}{Rescale}{\param{int}{ width}, \param{int}{ height}}
 
-Changes the size of the image in-place: after a call to this function, the
-image will have the given width and height.
+Changes the size of the image in-place by scaling it: after a call to this function, 
+the image will have the given width and height.
 
 Returns the (modified) image itself.
 
@@ -841,6 +849,24 @@ Returns the (modified) image itself.
 \helpref{Scale}{wximagescale}
 
 
+\membersection{wxImage::Resize}\label{wximageresize}
+
+\func{wxImage \&}{Resize}{\param{const wxSize\&}{ size}, \param{const wxPoint&}{ pos}, \param{int}{ red = -1}, \param{int}{ green = -1}, \param{int}{ blue = -1}}
+
+Changes the size of the image in-place without scaling it by adding either a border 
+with the given colour or cropping as necessary. The image is pasted into a new 
+image with the given {\it size} and background colour at the position {\it pos} 
+relative to the upper left of the new image. If {\it red = green = blue = -1} 
+then use either the  current mask colour if set or find, use, and set a 
+suitable mask colour for any newly exposed areas.
+
+Returns the (modified) image itself.
+
+\wxheading{See also}
+
+\helpref{Size}{wximagesize}
+
+
 \membersection{wxImage::Rotate}\label{wximagerotate}
 
 \func{wxImage}{Rotate}{\param{double}{ angle}, \param{const wxPoint\& }{rotationCentre},
@@ -979,6 +1005,22 @@ Example:
 \helpref{Rescale}{wximagerescale}
 
 
+\membersection{wxImage::Size}\label{wximagesize}
+
+\constfunc{wxImage}{Size}{\param{const wxSize\&}{ size}, \param{const wxPoint&}{ pos}, \param{int}{ red = -1}, \param{int}{ green = -1}, \param{int}{ blue = -1}}
+
+Returns a resized version of this image without scaling it by adding either a border 
+with the given colour or cropping as necessary. The image is pasted into a new 
+image with the given {\it size} and background colour at the position {\it pos} 
+relative to the upper left of the new image. If {\it red = green = blue = -1} 
+then use either the current mask colour if set or find, use, and set a 
+suitable mask colour for any newly exposed areas.
+
+\wxheading{See also}
+
+\helpref{Resize}{wximageresize}
+
+
 \membersection{wxImage::SetAlpha}\label{wximagesetalpha}
 
 \func{void}{SetAlpha}{\param{unsigned char *}{alpha = {\tt NULL}}}
@@ -1093,6 +1135,15 @@ be set directly. In that case you will have to get access to the image data
 using the \helpref{GetData}{wximagegetdata} method.
 
 
+\membersection{wxImage::SetRGB}\label{wximagesetrgbrect}
+
+\func{void}{SetRGB}{\param{wxRect \& }{rect}, \param{unsigned char }{red}, \param{unsigned char }{green}, \param{unsigned char }{blue}}
+
+Sets the colour of the pixels within the given rectangle. This routine performs
+bounds-checks for the coordinate so it can be considered a safe way to manipulate the
+data.
+
+
 \membersection{wxImage::operator $=$}\label{wximageassign}
 
 \func{wxImage\& }{operator $=$}{\param{const wxImage\& }{image}}
diff --git a/docs/latex/wx/rect.tex b/docs/latex/wx/rect.tex
index b537fd15ac..8e3c6bf1de 100644
--- a/docs/latex/wx/rect.tex
+++ b/docs/latex/wx/rect.tex
@@ -239,6 +239,14 @@ Returns {\tt true} if this rectangle has a non empty intersection with the
 rectangle {\it rect} and {\tt false} otherwise.
 
 
+\membersection{wxRect::IsEmpty}\label{wxrectisempty}
+
+\constfunc{bool}{IsEmpty}{}
+
+Returns {\tt true} if this rectangle has a width or height less than or equal to 
+0 and {\tt false} otherwise.
+
+
 \membersection{wxRect::Offset}\label{wxrectoffset}
 
 \func{void}{Offset}{\param{wxCoord }{dx}, \param{wxCoord }{dy}}
diff --git a/include/wx/artprov.h b/include/wx/artprov.h
index 4afdfad882..3576b4bad5 100644
--- a/include/wx/artprov.h
+++ b/include/wx/artprov.h
@@ -137,6 +137,10 @@ public:
                           const wxArtClient& client = wxART_OTHER,
                           const wxSize& size = wxDefaultSize);
 
+    // Get the size of an icon from a specific wxArtClient, queries 
+    // the topmost provider if platform_dependent = false
+    static wxSize GetSize(const wxArtClient& client, bool platform_dependent = false);
+
 protected:
     friend class wxArtProviderModule;
     // Initializes default provider
@@ -146,6 +150,12 @@ protected:
     // Destroy caches & all providers
     static void CleanUpProviders();
 
+    // Get the default size of an icon for a specific client
+    virtual wxSize DoGetSize(const wxArtClient& client) 
+    {
+        return GetSize(client, true);
+    }
+                             
     // Derived classes must override this method to create requested
     // art resource. This method is called only once per instance's
     // lifetime for each requested wxArtID.
diff --git a/include/wx/gdicmn.h b/include/wx/gdicmn.h
index a454155616..968feded88 100644
--- a/include/wx/gdicmn.h
+++ b/include/wx/gdicmn.h
@@ -346,6 +346,8 @@ public:
     wxSize GetSize() const { return wxSize(width, height); }
     void SetSize( const wxSize &s ) { width = s.GetWidth(); height = s.GetHeight(); }
 
+    bool IsEmpty() const { return (width <= 0) || (height <= 0); }
+
     wxPoint GetTopLeft() const { return GetPosition(); }
     wxPoint GetLeftTop() const { return GetTopLeft(); }
     void SetTopLeft(const wxPoint &p) { SetPosition(p); }
diff --git a/include/wx/image.h b/include/wx/image.h
index 77a6cb84f3..61f54d16cf 100644
--- a/include/wx/image.h
+++ b/include/wx/image.h
@@ -178,7 +178,14 @@ public:
     wxImage Copy() const;
 
     // return the new image with size width*height
-    wxImage GetSubImage( const wxRect& ) const;
+    wxImage GetSubImage( const wxRect& rect) const;
+
+    // Paste the image or part of this image into an image of the given size at the pos
+    //  any newly exposed areas will be filled with the rgb colour
+    //  by default if r = g = b = -1 then fill with this image's mask colour or find and 
+    //  set a suitable mask colour
+    wxImage Size( const wxSize& size, const wxPoint& pos, 
+                  int r = -1, int g = -1, int b = -1 ) const;
 
     // pastes image into this instance and takes care of
     // the mask colour and out of bounds problems
@@ -192,6 +199,10 @@ public:
     // rescales the image in place
     wxImage& Rescale( int width, int height ) { return *this = Scale(width, height); }
 
+    // resizes the image in place
+    wxImage& Resize( const wxSize& size, const wxPoint& pos, 
+                     int r = -1, int g = -1, int b = -1 ) { return *this = Size(size, pos, r, g, b); }
+
     // Rotates the image about the given point, 'angle' radians.
     // Returns the rotated image, leaving this image intact.
     wxImage Rotate(double angle, const wxPoint & centre_of_rotation,
@@ -210,6 +221,7 @@ public:
 
     // these routines are slow but safe
     void SetRGB( int x, int y, unsigned char r, unsigned char g, unsigned char b );
+    void SetRGB( const wxRect& rect, unsigned char r, unsigned char g, unsigned char b );
     unsigned char GetRed( int x, int y ) const;
     unsigned char GetGreen( int x, int y ) const;
     unsigned char GetBlue( int x, int y ) const;
@@ -280,6 +292,9 @@ public:
 
     // Mask functions
     void SetMaskColour( unsigned char r, unsigned char g, unsigned char b );
+    // Get the current mask colour or find a suitable colour
+    // returns true if using current mask colour
+    bool GetOrFindMaskColour( unsigned char *r, unsigned char *g, unsigned char *b ) const;
     unsigned char GetMaskRed() const;
     unsigned char GetMaskGreen() const;
     unsigned char GetMaskBlue() const;
diff --git a/src/common/artprov.cpp b/src/common/artprov.cpp
index 0b8018556c..5ebdb6aaa2 100644
--- a/src/common/artprov.cpp
+++ b/src/common/artprov.cpp
@@ -151,14 +151,16 @@ wxArtProviderCache *wxArtProvider::sm_cache = NULL;
 
 /*static*/ wxBitmap wxArtProvider::GetBitmap(const wxArtID& id,
                                              const wxArtClient& client,
-                                             const wxSize& size)
+                                             const wxSize& reqSize)
 {
     // safety-check against writing client,id,size instead of id,client,size:
     wxASSERT_MSG( client.Last() == _T('C'), _T("invalid 'client' parameter") );
 
     wxCHECK_MSG( sm_providers, wxNullBitmap, _T("no wxArtProvider exists") );
 
-    wxString hashId = wxArtProviderCache::ConstructHashID(id, client, size);
+    wxSize bestSize = (reqSize != wxDefaultSize) ? reqSize : GetSize(client);
+
+    wxString hashId = wxArtProviderCache::ConstructHashID(id, client, bestSize);
 
     wxBitmap bmp;
     if ( !sm_cache->GetBitmap(hashId, &bmp) )
@@ -166,15 +168,25 @@ wxArtProviderCache *wxArtProvider::sm_cache = NULL;
         for (wxArtProvidersList::compatibility_iterator node = sm_providers->GetFirst();
              node; node = node->GetNext())
         {
-            bmp = node->GetData()->CreateBitmap(id, client, size);
+            bmp = node->GetData()->CreateBitmap(id, client, bestSize);
             if ( bmp.Ok() )
             {
 #if wxUSE_IMAGE
-                if ( size != wxDefaultSize &&
-                     (bmp.GetWidth() != size.x || bmp.GetHeight() != size.y) )
+                int bmp_w = bmp.GetWidth();
+                int bmp_h = bmp.GetHeight();
+                // want default size but it's smaller, paste into transparent image
+                if ((reqSize == wxDefaultSize) && 
+                    (bmp_h < bestSize.x) && (bmp_w < bestSize.y))
+                {
+                     wxPoint offset((bestSize.x - bmp_w)/2, (bestSize.y - bmp_h)/2);
+                     wxImage img = bmp.ConvertToImage();
+                     img.Resize(bestSize, offset);
+                     bmp = wxBitmap(img);
+                }
+                else if ( (bmp_w != bestSize.x) || (bmp_h != bestSize.y) )
                 {
                     wxImage img = bmp.ConvertToImage();
-                    img.Rescale(size.x, size.y);
+                    img.Rescale(bestSize.x, bestSize.y);
                     bmp = wxBitmap(img);
                 }
 #endif
@@ -203,6 +215,42 @@ wxArtProviderCache *wxArtProvider::sm_cache = NULL;
     return icon;
 }
 
+#ifdef __WXGTK__
+    #include <gtk/gtk.h>
+    extern GtkIconSize wxArtClientToIconSize(const wxArtClient& client);
+#endif // __WXGTK__
+
+/*static*/ wxSize wxArtProvider::GetSize(const wxArtClient& client, 
+                                         bool platform_dependent)
+{
+    if (!platform_dependent)
+    {
+        wxArtProvidersList::compatibility_iterator node = sm_providers->GetFirst();
+        if (node)
+            return node->GetData()->DoGetSize(client);
+            
+        // else return platform dependent size
+    }    
+    
+#ifdef __WXGTK__
+    GtkIconSize gtk_size = wxArtClientToIconSize(client);
+    gint width, height;
+    gtk_icon_size_lookup( gtk_size, &width, &height);
+    return wxSize(width, height);
+#else 
+    if (client == wxART_TOOLBAR)
+        return wxSize(32, 32);
+    else if (client == wxART_MENU)
+        return wxSize(16, 15);
+    else if (client == wxART_CMN_DIALOG || client == wxART_MESSAGE_BOX)
+        return wxSize(32, 32);
+    else if (client == wxART_BUTTON)
+        return wxSize(16, 15);
+    else
+        return wxSize(16, 15); // this is arbitrary    
+#endif 
+}
+
 
 class wxArtProviderModule: public wxModule
 {
diff --git a/src/common/image.cpp b/src/common/image.cpp
index 627bcadcf2..3f90f3238a 100644
--- a/src/common/image.cpp
+++ b/src/common/image.cpp
@@ -603,6 +603,44 @@ wxImage wxImage::GetSubImage( const wxRect &rect ) const
     return image;
 }
 
+wxImage wxImage::Size( const wxSize& size, const wxPoint& pos, 
+                       int r_, int g_, int b_ ) const
+{
+    wxImage image;
+
+    wxCHECK_MSG( Ok(), image, wxT("invalid image") );
+    wxCHECK_MSG( (size.GetWidth() > 0) && (size.GetHeight() > 0), image, wxT("invalid size") );
+
+    int width = GetWidth(), height = GetHeight();
+    image.Create(size.GetWidth(), size.GetHeight(), false);
+
+    unsigned char r = (unsigned char)r_;
+    unsigned char g = (unsigned char)g_;
+    unsigned char b = (unsigned char)b_;
+    if ((r_ == -1) && (g_ == -1) && (b_ == -1))
+    {
+        GetOrFindMaskColour( &r, &g, &b );
+        image.SetMaskColour(r, g, b);
+    }
+
+    image.SetRGB(wxRect(), r, g, b);
+
+    wxRect subRect(pos.x, pos.y, width, height);
+    wxRect finalRect(0, 0, size.GetWidth(), size.GetHeight());
+
+    subRect.Intersect(finalRect);
+
+    if (!subRect.IsEmpty())
+    {
+        if ((subRect.GetWidth() == width) && (subRect.GetHeight() == height))
+            image.Paste(*this, pos.x, pos.y);
+        else
+            image.Paste(GetSubImage(subRect), pos.x, pos.y);
+    }
+
+    return image;
+}
+
 void wxImage::Paste( const wxImage &image, int x, int y )
 {
     wxCHECK_RET( Ok(), wxT("invalid image") );
@@ -633,6 +671,7 @@ void wxImage::Paste( const wxImage &image, int x, int y )
     if (height < 1) return;
 
     if ((!HasMask() && !image.HasMask()) ||
+        (HasMask() && !image.HasMask()) ||
        ((HasMask() && image.HasMask() &&
          (GetMaskRed()==image.GetMaskRed()) &&
          (GetMaskGreen()==image.GetMaskGreen()) &&
@@ -759,6 +798,42 @@ void wxImage::SetRGB( int x, int y, unsigned char r, unsigned char g, unsigned c
     M_IMGDATA->m_data[ pos+2 ] = b;
 }
 
+void wxImage::SetRGB( const wxRect& rect_, unsigned char r, unsigned char g, unsigned char b )
+{
+    wxCHECK_RET( Ok(), wxT("invalid image") );
+
+    wxRect rect(rect_);
+    wxRect imageRect(0, 0, GetWidth(), GetHeight());
+    if ( rect == wxRect() )
+    {
+        rect = imageRect;
+    }
+    else
+    {
+        wxCHECK_RET( imageRect.Inside(rect.GetTopLeft()) && 
+                     imageRect.Inside(rect.GetBottomRight()), 
+                     wxT("invalid bounding rectangle") );
+    }
+
+    int x1 = rect.GetLeft(),
+        y1 = rect.GetTop(),
+        x2 = rect.GetRight() + 1,
+        y2 = rect.GetBottom() + 1;
+
+    unsigned char *data = NULL;
+    int x, y, width = GetWidth();
+    for (y = y1; y < y2; y++)
+    {
+        data = M_IMGDATA->m_data + (y*width + x1)*3;
+        for (x = x1; x < x2; x++)
+        {
+            *data++ = r;
+            *data++ = g;
+            *data++ = b;
+        }
+    }
+}
+
 unsigned char wxImage::GetRed( int x, int y ) const
 {
     wxCHECK_MSG( Ok(), 0, wxT("invalid image") );
@@ -991,6 +1066,24 @@ void wxImage::SetMaskColour( unsigned char r, unsigned char g, unsigned char b )
     M_IMGDATA->m_hasMask = true;
 }
 
+bool wxImage::GetOrFindMaskColour( unsigned char *r, unsigned char *g, unsigned char *b ) const
+{
+    wxCHECK_MSG( Ok(), false, wxT("invalid image") );
+
+    if (M_IMGDATA->m_hasMask)
+    {
+        if (r) *r = M_IMGDATA->m_maskRed;
+        if (g) *g = M_IMGDATA->m_maskGreen;
+        if (b) *b = M_IMGDATA->m_maskBlue;
+        return true;
+    }
+    else
+    {
+        FindFirstUnusedColour(r, g, b);
+        return false;
+    }
+}
+
 unsigned char wxImage::GetMaskRed() const
 {
     wxCHECK_MSG( Ok(), 0, wxT("invalid image") );
diff --git a/src/gtk/artgtk.cpp b/src/gtk/artgtk.cpp
index 209c58e674..47aa4c93db 100644
--- a/src/gtk/artgtk.cpp
+++ b/src/gtk/artgtk.cpp
@@ -125,7 +125,7 @@ static const char *wxArtIDToStock(const wxArtID& id)
     #undef ART
 }
 
-static GtkIconSize wxArtClientToIconSize(const wxArtClient& client)
+GtkIconSize wxArtClientToIconSize(const wxArtClient& client)
 {
     if (client == wxART_TOOLBAR)
         return GTK_ICON_SIZE_LARGE_TOOLBAR;
diff --git a/src/gtk1/artgtk.cpp b/src/gtk1/artgtk.cpp
index 209c58e674..47aa4c93db 100644
--- a/src/gtk1/artgtk.cpp
+++ b/src/gtk1/artgtk.cpp
@@ -125,7 +125,7 @@ static const char *wxArtIDToStock(const wxArtID& id)
     #undef ART
 }
 
-static GtkIconSize wxArtClientToIconSize(const wxArtClient& client)
+GtkIconSize wxArtClientToIconSize(const wxArtClient& client)
 {
     if (client == wxART_TOOLBAR)
         return GTK_ICON_SIZE_LARGE_TOOLBAR;
diff --git a/src/mac/carbon/cursor.cpp b/src/mac/carbon/cursor.cpp
index 9a271f6b1c..6bb1ff40bc 100644
--- a/src/mac/carbon/cursor.cpp
+++ b/src/mac/carbon/cursor.cpp
@@ -303,20 +303,40 @@ void wxCursor::CreateFromImage(const wxImage & image)
 {
     m_refData = new wxCursorRefData;
 
-    wxImage image16 = image.Scale(16,16) ;
-       unsigned char * rgbBits = image16.GetData();
+    int w = 16;
+    int h = 16;
+
+    int hotSpotX = image.GetOptionInt(wxIMAGE_OPTION_CUR_HOTSPOT_X);
+    int hotSpotY = image.GetOptionInt(wxIMAGE_OPTION_CUR_HOTSPOT_Y);
+    int image_w = image.GetWidth();
+    int image_h = image.GetHeight();
+
+    wxASSERT_MSG( hotSpotX >= 0 && hotSpotX < image_w &&
+                  hotSpotY >= 0 && hotSpotY < image_h,
+                  _T("invalid cursor hot spot coordinates") );
+
+    wxImage image16(image); // final image of correct size
  
+    // if image is too small then place it in the center, resize it if too big
+    if ((w > image_w) && (h > image_h))
+    {
+        wxPoint offset((w - image_w)/2, (h - image_h)/2);
+        hotSpotX = hotSpotX + offset.x;
+        hotSpotY = hotSpotY + offset.y;
     
-    int w = image16.GetWidth()  ;
-    int h = image16.GetHeight() ;
+        image16 = image.Size(wxSize(w, h), offset);
+    }
+    else if ((w != image_w) || (h != image_h))
+    {
+        hotSpotX = int(hotSpotX * double(w) / double(image_w)); 
+        hotSpotY = int(hotSpotY * double(h) / double(image_h)); 
+
+        image16 = image.Scale(w, h);
+    }
+
+    unsigned char * rgbBits = image16.GetData();
     bool bHasMask = image16.HasMask() ;
 
-       int hotSpotX = image16.GetOptionInt(wxIMAGE_OPTION_CUR_HOTSPOT_X);
-    int hotSpotY = image16.GetOptionInt(wxIMAGE_OPTION_CUR_HOTSPOT_Y);
-    if (hotSpotX < 0 || hotSpotX >= w)
-            hotSpotX = 0;
-    if (hotSpotY < 0 || hotSpotY >= h)
-            hotSpotY = 0;
             
     PixMapHandle pm = (PixMapHandle) NewHandleClear( sizeof (PixMap))  ;
     short extent = 16 ;
diff --git a/src/mac/classic/cursor.cpp b/src/mac/classic/cursor.cpp
index b780a675c9..475c473b91 100644
--- a/src/mac/classic/cursor.cpp
+++ b/src/mac/classic/cursor.cpp
@@ -130,20 +130,39 @@ void wxCursor::CreateFromImage(const wxImage & image)
 {
     m_refData = new wxCursorRefData;
 
-    wxImage image16 = image.Scale(16,16) ;
-       unsigned char * rgbBits = image16.GetData();
+    int w = 16;
+    int h = 16;
  
+    int hotSpotX = image.GetOptionInt(wxIMAGE_OPTION_CUR_HOTSPOT_X);
+    int hotSpotY = image.GetOptionInt(wxIMAGE_OPTION_CUR_HOTSPOT_Y);
+    int image_w = image.GetWidth();
+    int image_h = image.GetHeight();
     
-    int w = image16.GetWidth()  ;
-    int h = image16.GetHeight() ;
-    bool bHasMask = image16.HasMask() ;
+    wxASSERT_MSG( hotSpotX >= 0 && hotSpotX < image_w &&
+                  hotSpotY >= 0 && hotSpotY < image_h,
+                  _T("invalid cursor hot spot coordinates") );
+
+    wxImage image16(image); // final image of correct size
+
+    // if image is too small then place it in the center, resize it if too big
+    if ((w > image_w) && (h > image_h))
+    {
+        wxPoint offset((w - image_w)/2, (h - image_h)/2);
+        hotSpotX = hotSpotX + offset.x;
+        hotSpotY = hotSpotY + offset.y;
+
+        image16 = image.Size(wxSize(w, h), offset);
+    }
+    else if ((w != image_w) || (h != image_h))
+    {
+        hotSpotX = int(hotSpotX * double(w) / double(image_w)); 
+        hotSpotY = int(hotSpotY * double(h) / double(image_h)); 
 
-       int hotSpotX = image16.GetOptionInt(wxIMAGE_OPTION_CUR_HOTSPOT_X);
-    int hotSpotY = image16.GetOptionInt(wxIMAGE_OPTION_CUR_HOTSPOT_Y);
-    if (hotSpotX < 0 || hotSpotX >= w)
-            hotSpotX = 0;
-    if (hotSpotY < 0 || hotSpotY >= h)
-            hotSpotY = 0;
+        image16 = image.Scale(w, h);
+    }
+
+    unsigned char * rgbBits = image16.GetData();
+    bool bHasMask = image16.HasMask() ;
             
 #if 0
     // monochrome implementation
diff --git a/src/msw/cursor.cpp b/src/msw/cursor.cpp
index f546bd06b3..23495af1aa 100644
--- a/src/msw/cursor.cpp
+++ b/src/msw/cursor.cpp
@@ -180,19 +180,37 @@ wxCursor::wxCursor(const wxImage& image)
     const int w = wxCursorRefData::GetStandardWidth();
     const int h = wxCursorRefData::GetStandardHeight();
 
-    const int hotSpotX = image.GetOptionInt(wxIMAGE_OPTION_CUR_HOTSPOT_X);
-    const int hotSpotY = image.GetOptionInt(wxIMAGE_OPTION_CUR_HOTSPOT_Y);
+    int hotSpotX = image.GetOptionInt(wxIMAGE_OPTION_CUR_HOTSPOT_X);
+    int hotSpotY = image.GetOptionInt(wxIMAGE_OPTION_CUR_HOTSPOT_Y);
+    int image_w = image.GetWidth();
+    int image_h = image.GetHeight();
 
-    wxASSERT_MSG( hotSpotX >= 0 && hotSpotX < w &&
-                    hotSpotY >= 0 && hotSpotY < h,
+    wxASSERT_MSG( hotSpotX >= 0 && hotSpotX < image_w &&
+                  hotSpotY >= 0 && hotSpotY < image_h,
                   _T("invalid cursor hot spot coordinates") );
 
-    HCURSOR hcursor = wxBitmapToHCURSOR
-                      (
-                        wxBitmap(image.Scale(w, h)),
-                        hotSpotX,
-                        hotSpotY
-                      );
+    wxImage imageSized(image); // final image of correct size
+
+    // if image is too small then place it in the center, resize it if too big
+    if ((w > image_w) && (h > image_h))
+    {
+        wxPoint offset((w - image_w)/2, (h - image_h)/2);
+        hotSpotX = hotSpotX + offset.x;
+        hotSpotY = hotSpotY + offset.y;
+
+        imageSized = image.Size(wxSize(w, h), offset);
+    }
+    else if ((w != image_w) || (h != image_h))
+    {
+        hotSpotX = int(hotSpotX * double(w) / double(image_w)); 
+        hotSpotY = int(hotSpotY * double(h) / double(image_h)); 
+
+        imageSized = image.Scale(w, h);
+    }
+
+    HCURSOR hcursor = wxBitmapToHCURSOR( wxBitmap(imageSized), 
+                                         hotSpotX, hotSpotY );
+
     if ( !hcursor )
     {
         wxLogWarning(_("Failed to create cursor."));
-- 
2.47.2

