X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/0fc5dbf52a35041340cc1d20aefd81b65b8161c8..08670ea85abf4b4946a9ce64971b591d7b1ee30b:/src/common/imagfill.cpp diff --git a/src/common/imagfill.cpp b/src/common/imagfill.cpp index 42933301db..df260c0398 100644 --- a/src/common/imagfill.cpp +++ b/src/common/imagfill.cpp @@ -1,14 +1,12 @@ ///////////////////////////////////////////////////////////////////////////// -// Name: imagfill.cpp +// Name: src/common/imagfill.cpp // Purpose: FloodFill for wxImage -// Author: +// Author: Julian Smart // RCS-ID: $Id$ -// Copyright: +// Copyright: (c) Julian Smart // Licence: wxWindows licence ///////////////////////////////////////////////////////////////////////////// -#ifdef __GNUG__ -#endif // For compilers that support precompilation, includes "wx.h". #include "wx/wxprec.h" @@ -17,12 +15,14 @@ #pragma hdrstop #endif -#if wxUSE_IMAGE - -#include "wx/image.h" +#if wxUSE_IMAGE && !defined(__WXMSW__) +// we have no use for this code in wxMSW... #ifndef WX_PRECOMP #include "wx/brush.h" + #include "wx/dc.h" + #include "wx/dcmemory.h" + #include "wx/image.h" #endif // DoFloodFill @@ -30,40 +30,47 @@ // a color different from the start pixel is reached (wxFLOOD_SURFACE) // or fill color is reached (wxFLOOD_BORDER) -bool wxImage::MatchPixel(int x, int y, int w, int h, const wxColour & c) +static bool LINKAGEMODE MatchPixel(wxImage *img, int x, int y, int w, int h, const wxColour& c) { if ((x<0)||(x>=w)||(y<0)||(y>=h)) return false; - unsigned char r = GetRed(x,y); - unsigned char g = GetGreen(x,y); - unsigned char b = GetBlue(x,y); + unsigned char r = img->GetRed(x,y); + unsigned char g = img->GetGreen(x,y); + unsigned char b = img->GetBlue(x,y); return c.Red() == r && c.Green() == g && c.Blue() == b ; } -bool wxImage::MatchBoundaryPixel(int x, int y, int w, int h, const wxColour & fill, const wxColour & bound) +static bool LINKAGEMODE MatchBoundaryPixel(wxImage *img, int x, int y, int w, int h, const wxColour & fill, const wxColour& bound) { - if ((x<0)||(x>=w)||(y<0)||(y>=h)) return TRUE; - - unsigned char r = GetRed(x,y); - unsigned char g = GetGreen(x,y); - unsigned char b = GetBlue(x,y); - if ( fill.Red() == r && fill.Green() == g && fill.Blue() == b ) return TRUE; - if ( bound.Red() == r && bound.Green() == g && bound.Blue() == b ) return TRUE; - return FALSE ; + if ((x<0)||(x>=w)||(y<0)||(y>=h)) return true; + + unsigned char r = img->GetRed(x,y); + unsigned char g = img->GetGreen(x,y); + unsigned char b = img->GetBlue(x,y); + if ( fill.Red() == r && fill.Green() == g && fill.Blue() == b ) + return true; + if ( bound.Red() == r && bound.Green() == g && bound.Blue() == b ) + return true; + return false; } -void wxImage::DoFloodFill (wxCoord x, wxCoord y, const wxBrush & fillBrush, - const wxColour& testColour, int style /*=wxFLOOD_SURFACE */, - int LogicalFunction /*= wxCOPY, currently unused */) +static void LINKAGEMODE +wxImageFloodFill(wxImage *image, + wxCoord x, wxCoord y, const wxBrush & fillBrush, + const wxColour& testColour, int style, + int WXUNUSED(LogicalFunction)) { /* A diamond flood-fill using a circular queue system. Each pixel surrounding the current pixel is added to the queue if it meets the criteria, then is retrieved in - its turn. Code originally based on http://www.drawit.co.nz/Developers.htm */ + its turn. Code originally based on http://www.drawit.co.nz/Developers.htm, + with explicit permission to use this for wxWidgets granted by Andrew Empson + (no copyright claimed) + */ - int width = GetWidth(); - int height = GetHeight(); + int width = image->GetWidth(); + int height = image->GetHeight(); //Draw using a pen made from the current brush colour //Potentially allows us to use patterned flood fills in future code @@ -76,9 +83,9 @@ void wxImage::DoFloodFill (wxCoord x, wxCoord y, const wxBrush & fillBrush, if (style == wxFLOOD_SURFACE) { //if wxFLOOD_SURFACE, if fill colour is same as required, we don't do anything - if ( GetRed(x,y) != r - || GetGreen(x,y) != g - || GetBlue (x,y) != b ) + if ( image->GetRed(x,y) != r + || image->GetGreen(x,y) != g + || image->GetBlue (x,y) != b ) { //prepare memory for queue //queue save, start, read @@ -101,55 +108,55 @@ void wxImage::DoFloodFill (wxCoord x, wxCoord y, const wxBrush & fillBrush, *qs=yt=y; qs++; - SetRGB(xt,yt,r,g,b); + image->SetRGB(xt,yt,r,g,b); //Main queue loop while(qr!=qs) { //Add new members to queue //Above current pixel - if(MatchPixel(xt,yt-1,width,height,testColour)) + if(MatchPixel(image,xt,yt-1,width,height,testColour)) { *qs=xt; qs++; *qs=yt-1; qs++; - SetRGB(xt,yt-1,r,g,b); + image->SetRGB(xt,yt-1,r,g,b); //Loop back to beginning of queue if(qs>=(qst+qSz)) qs=qst; } //Below current pixel - if(MatchPixel(xt,yt+1,width,height,testColour)) + if(MatchPixel(image,xt,yt+1,width,height,testColour)) { *qs=xt; qs++; *qs=yt+1; qs++; - SetRGB(xt,yt+1,r,g,b); + image->SetRGB(xt,yt+1,r,g,b); if(qs>=(qst+qSz)) qs=qst; } //Left of current pixel - if(MatchPixel(xt-1,yt,width,height,testColour)) + if(MatchPixel(image,xt-1,yt,width,height,testColour)) { *qs=xt-1; qs++; *qs=yt; qs++; - SetRGB(xt-1,yt,r,g,b); + image->SetRGB(xt-1,yt,r,g,b); if(qs>=(qst+qSz)) qs=qst; } //Right of current pixel - if(MatchPixel(xt+1,yt,width,height,testColour)) + if(MatchPixel(image,xt+1,yt,width,height,testColour)) { *qs=xt+1; qs++; *qs=yt; qs++; - SetRGB(xt+1,yt,r,g,b); + image->SetRGB(xt+1,yt,r,g,b); if(qs>=(qst+qSz)) qs=qst; } @@ -164,17 +171,17 @@ void wxImage::DoFloodFill (wxCoord x, wxCoord y, const wxBrush & fillBrush, //Go Back to beginning of loop } - delete [] qst ; + delete[] qst; } } else { //style is wxFLOOD_BORDER // fill up to testColor border - if already testColour don't do anything - if ( GetRed(x,y) != testColour.Red() - || GetGreen(x,y) != testColour.Green() - || GetBlue(x,y) != testColour.Blue() ) - { + if ( image->GetRed(x,y) != testColour.Red() + || image->GetGreen(x,y) != testColour.Green() + || image->GetBlue(x,y) != testColour.Blue() ) + { //prepare memory for queue //queue save, start, read size_t *qs, *qst, *qr; @@ -196,55 +203,55 @@ void wxImage::DoFloodFill (wxCoord x, wxCoord y, const wxBrush & fillBrush, *qs=yt=y; qs++; - SetRGB(xt,yt,r,g,b); + image->SetRGB(xt,yt,r,g,b); //Main queue loop - while(qr!=qs) + while (qr!=qs) { //Add new members to queue //Above current pixel - if(!MatchBoundaryPixel(xt,yt-1,width,height,fillColour,testColour)) + if(!MatchBoundaryPixel(image,xt,yt-1,width,height,fillColour,testColour)) { *qs=xt; qs++; *qs=yt-1; qs++; - SetRGB(xt,yt-1,r,g,b); + image->SetRGB(xt,yt-1,r,g,b); //Loop back to beginning of queue if(qs>=(qst+qSz)) qs=qst; } //Below current pixel - if(!MatchBoundaryPixel(xt,yt+1,width,height,fillColour,testColour)) + if(!MatchBoundaryPixel(image,xt,yt+1,width,height,fillColour,testColour)) { *qs=xt; qs++; *qs=yt+1; qs++; - SetRGB(xt,yt+1,r,g,b); + image->SetRGB(xt,yt+1,r,g,b); if(qs>=(qst+qSz)) qs=qst; } //Left of current pixel - if(!MatchBoundaryPixel(xt-1,yt,width,height,fillColour,testColour)) + if(!MatchBoundaryPixel(image,xt-1,yt,width,height,fillColour,testColour)) { *qs=xt-1; qs++; *qs=yt; qs++; - SetRGB(xt-1,yt,r,g,b); + image->SetRGB(xt-1,yt,r,g,b); if(qs>=(qst+qSz)) qs=qst; } //Right of current pixel - if(!MatchBoundaryPixel(xt+1,yt,width,height,fillColour,testColour)) + if(!MatchBoundaryPixel(image,xt+1,yt,width,height,fillColour,testColour)) { *qs=xt+1; qs++; *qs=yt; qs++; - SetRGB(xt+1,yt,r,g,b); + image->SetRGB(xt+1,yt,r,g,b); if(qs>=(qst+qSz)) qs=qst; } @@ -259,11 +266,60 @@ void wxImage::DoFloodFill (wxCoord x, wxCoord y, const wxBrush & fillBrush, //Go Back to beginning of loop } - delete [] qst ; + delete[] qst; } } //all done, } -#endif // wxUSE_IMAGE +bool wxDoFloodFill(wxDC *dc, wxCoord x, wxCoord y, + const wxColour& col, wxFloodFillStyle style) +{ + if (dc->GetBrush().IsTransparent()) + return true; + + int height = 0; + int width = 0; + dc->GetSize(&width, &height); + + //it would be nice to fail if we don't get a sensible size... + wxCHECK_MSG(width >= 1 && height >= 1, false, + wxT("In FloodFill, dc.GetSize routine failed, method not supported by this DC")); + + const int x_dev = dc->LogicalToDeviceX(x); + const int y_dev = dc->LogicalToDeviceY(y); + + // if start point is outside dc, can't do anything + if (!wxRect(0, 0, width, height).Contains(x_dev, y_dev)) + return false; + + wxBitmap bitmap(width, height); + wxMemoryDC memdc(bitmap); + // match dc scales + double sx, sy; + dc->GetUserScale(&sx, &sy); + memdc.SetUserScale(sx, sy); + dc->GetLogicalScale(&sx, &sy); + memdc.SetLogicalScale(sx, sy); + + // get logical size and origin + const int w_log = dc->DeviceToLogicalXRel(width); + const int h_log = dc->DeviceToLogicalYRel(height); + const int x0_log = dc->DeviceToLogicalX(0); + const int y0_log = dc->DeviceToLogicalY(0); + + memdc.Blit(0, 0, w_log, h_log, dc, x0_log, y0_log); + memdc.SelectObject(wxNullBitmap); + + wxImage image = bitmap.ConvertToImage(); + wxImageFloodFill(&image, x_dev, y_dev, dc->GetBrush(), col, style, + dc->GetLogicalFunction()); + bitmap = wxBitmap(image); + memdc.SelectObject(bitmap); + dc->Blit(x0_log, y0_log, w_log, h_log, &memdc, 0, 0); + + return true; +} + +#endif // wxUSE_IMAGE