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
This commit is contained in:
Robert Roebling 2005-03-04 18:33:57 +00:00
parent 0b40f3d80b
commit b737ad10de
14 changed files with 334 additions and 44 deletions

View File

@ -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}

View File

@ -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}}

View File

@ -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}}

View File

@ -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}}

View File

@ -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.

View File

@ -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); }

View File

@ -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;

View File

@ -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
{

View File

@ -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") );

View File

@ -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;

View File

@ -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;

View File

@ -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 ;

View File

@ -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") );
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;
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));
image16 = image.Scale(w, h);
}
unsigned char * rgbBits = image16.GetData();
bool bHasMask = image16.HasMask() ;
#if 0
// monochrome implementation

View File

@ -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."));