From: Julian Smart Date: Mon, 1 Apr 2002 21:40:42 +0000 (+0000) Subject: Applied FloodFill patch X-Git-Url: https://git.saurik.com/wxWidgets.git/commitdiff_plain/b1699cd397f7db0193491c8498608578b43db12b Applied FloodFill patch git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@14894 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- diff --git a/distrib/msw/msw.rsp b/distrib/msw/msw.rsp index 40b85a13af..b705079f2a 100644 --- a/distrib/msw/msw.rsp +++ b/distrib/msw/msw.rsp @@ -51,8 +51,6 @@ src/*.bat src/common/dosyacc.c src/common/doslex.c -src/common/y_tab.c -src/common/lex_yy.c src/common/*.rc src/msw/*.cpp diff --git a/docs/latex/wx/dc.tex b/docs/latex/wx/dc.tex index b2d9573af9..dc731b363d 100644 --- a/docs/latex/wx/dc.tex +++ b/docs/latex/wx/dc.tex @@ -497,7 +497,8 @@ the {\it current brush colour}, and using a style: \item wxFLOOD\_BORDER: the area to be flooded is bounded by the given colour. \end{itemize} -{\it Note:} this function is available in MS Windows only. +{\it Note:} The present implementation for non-Windows platforms may fail to find +colour borders if the pixels do not match the colour exactly. \membersection{wxDC::GetBackground}\label{wxdcgetbackground} diff --git a/include/wx/image.h b/include/wx/image.h index 7522d06854..786b76f3a2 100644 --- a/include/wx/image.h +++ b/include/wx/image.h @@ -175,6 +175,12 @@ public: bool SetMaskFromImage(const wxImage & mask, unsigned char mr, unsigned char mg, unsigned char mb); + void DoFloodFill (wxCoord x, wxCoord y, + const wxBrush & fillBrush, + const wxColour& testColour, + int style = wxFLOOD_SURFACE, + int LogicalFunction = wxCOPY /* currently unused */ ) ; + static bool CanRead( const wxString& name ); static int GetImageCount( const wxString& name, long type = wxBITMAP_TYPE_ANY ); virtual bool LoadFile( const wxString& name, long type = wxBITMAP_TYPE_ANY, int index = -1 ); @@ -264,6 +270,10 @@ protected: static wxList sm_handlers; private: + //these two are called by FloodFill + bool MatchPixel(int x, int y, int w, int h, const wxColour & c) ; + bool MatchBoundaryPixel(int x, int y, int w, int h, const wxColour & fill, const wxColour & bound) ; + friend class WXDLLEXPORT wxImageHandler; DECLARE_DYNAMIC_CLASS(wxImage) diff --git a/src/common/image.cpp b/src/common/image.cpp index d4f9ddac8c..f98926b073 100644 --- a/src/common/image.cpp +++ b/src/common/image.cpp @@ -820,6 +820,248 @@ bool wxImage::SetMaskFromImage(const wxImage& mask, return TRUE; } + +// DoFloodFill +// Fills with the colour extracted from fillBrush, starting at x,y until either +// 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) +{ + 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); + 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) +{ + 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 ; +} + + +void wxImage::DoFloodFill (wxCoord x, wxCoord y, const wxBrush & fillBrush, + const wxColour& testColour, int style /*=wxFLOOD_SURFACE */, + int LogicalFunction /*= wxCOPY, currently unused */) +{ + /* 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 */ + + int width = GetWidth(); + int height = GetHeight(); + + //Draw using a pen made from the current brush colour + //Potentially allows us to use patterned flood fills in future code + wxColour fillColour = fillBrush.GetColour(); + unsigned char r = fillColour.Red(); + unsigned char g = fillColour.Green(); + unsigned char b = fillColour.Blue(); + + //initial test : + 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 ) + { + //prepare memory for queue + //queue save, start, read + size_t *qs, *qst, *qr; + + //queue size (physical) + long qSz= height * width * 2; + qst = new size_t [qSz]; + + //temporary x and y locations + int xt, yt; + + for (int i=0; i < qSz; i++) + qst[i] = 0; + + // start queue + qs=qr=qst; + *qs=xt=x; + qs++; + *qs=yt=y; + qs++; + + 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)) + { + *qs=xt; + qs++; + *qs=yt-1; + qs++; + 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)) + { + *qs=xt; + qs++; + *qs=yt+1; + qs++; + 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)) + { + *qs=xt-1; + qs++; + *qs=yt; + qs++; + 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)) + { + *qs=xt+1; + qs++; + *qs=yt; + qs++; + SetRGB(xt+1,yt,r,g,b); + if(qs>=(qst+qSz)) qs=qst; + } + + //Retrieve current queue member + qr+=2; + + //Loop back to the beginning + if(qr>=(qst+qSz)) qr=qst; + xt=*qr; + yt=*(qr+1); + + //Go Back to beginning of loop + } + + 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() ) + { + //prepare memory for queue + //queue save, start, read + size_t *qs, *qst, *qr; + + //queue size (physical) + long qSz= height * width * 2; + qst = new size_t [qSz]; + + //temporary x and y locations + int xt, yt; + + for (int i=0; i < qSz; i++) + qst[i] = 0; + + // start queue + qs=qr=qst; + *qs=xt=x; + qs++; + *qs=yt=y; + qs++; + + SetRGB(xt,yt,r,g,b); + + //Main queue loop + while(qr!=qs) + { + //Add new members to queue + //Above current pixel + if(!MatchBoundaryPixel(xt,yt-1,width,height,fillColour,testColour)) + { + *qs=xt; + qs++; + *qs=yt-1; + qs++; + 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)) + { + *qs=xt; + qs++; + *qs=yt+1; + qs++; + 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)) + { + *qs=xt-1; + qs++; + *qs=yt; + qs++; + 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)) + { + *qs=xt+1; + qs++; + *qs=yt; + qs++; + SetRGB(xt+1,yt,r,g,b); + if(qs>=(qst+qSz)) qs=qst; + } + + //Retrieve current queue member + qr+=2; + + //Loop back to the beginning + if(qr>=(qst+qSz)) qr=qst; + xt=*qr; + yt=*(qr+1); + + //Go Back to beginning of loop + } + + delete [] qst ; + } + } + //all done, +} + + #if wxUSE_PALETTE // Palette functions diff --git a/src/gtk/dcclient.cpp b/src/gtk/dcclient.cpp index 2d4299ad5a..d903e9311c 100644 --- a/src/gtk/dcclient.cpp +++ b/src/gtk/dcclient.cpp @@ -19,6 +19,7 @@ #include "wx/dcmemory.h" #include "wx/image.h" #include "wx/module.h" +#include "wx/log.h" #include "wx/gtk/win_gtk.h" @@ -400,10 +401,37 @@ void wxWindowDC::DoGetSize( int* width, int* height ) const m_owner->GetSize(width, height); } -void wxWindowDC::DoFloodFill( wxCoord WXUNUSED(x), wxCoord WXUNUSED(y), - const wxColour &WXUNUSED(col), int WXUNUSED(style) ) +void wxWindowDC::DoFloodFill( wxCoord x, wxCoord y, + const wxColour & col, int style ) { - wxFAIL_MSG( wxT("wxWindowDC::DoFloodFill not implemented") ); + if (GetBrush().GetStyle() == wxTRANSPARENT) + { + wxLogDebug(wxT("In FloodFill, current Brush is transparent, no filling done")); + return ; + } + int height = 0; + int width = 0; + this->GetSize(&width, &height); + //it would be nice to fail if we don't get a sensible size... + if (width < 1 || height < 1) + { + wxLogError(wxT("In FloodFill, dc.GetSize routine failed, method not supported by this DC")); + return ; + } + + //this is much faster than doing the individual pixels + wxMemoryDC memdc; + wxBitmap bitmap(width, height); + memdc.SelectObject(bitmap); + memdc.Blit(0, 0, width, height, (wxDC*) this, 0, 0); + memdc.SelectObject(wxNullBitmap); + + wxImage image(bitmap); + image.DoFloodFill (x,y, GetBrush(), col, style, GetLogicalFunction()); + bitmap = wxBitmap(image); + memdc.SelectObject(bitmap); + this->Blit(0, 0, width, height, &memdc, 0, 0); + memdc.SelectObject(wxNullBitmap); } bool wxWindowDC::DoGetPixel( wxCoord x1, wxCoord y1, wxColour *col ) const diff --git a/src/gtk1/dcclient.cpp b/src/gtk1/dcclient.cpp index 2d4299ad5a..d903e9311c 100644 --- a/src/gtk1/dcclient.cpp +++ b/src/gtk1/dcclient.cpp @@ -19,6 +19,7 @@ #include "wx/dcmemory.h" #include "wx/image.h" #include "wx/module.h" +#include "wx/log.h" #include "wx/gtk/win_gtk.h" @@ -400,10 +401,37 @@ void wxWindowDC::DoGetSize( int* width, int* height ) const m_owner->GetSize(width, height); } -void wxWindowDC::DoFloodFill( wxCoord WXUNUSED(x), wxCoord WXUNUSED(y), - const wxColour &WXUNUSED(col), int WXUNUSED(style) ) +void wxWindowDC::DoFloodFill( wxCoord x, wxCoord y, + const wxColour & col, int style ) { - wxFAIL_MSG( wxT("wxWindowDC::DoFloodFill not implemented") ); + if (GetBrush().GetStyle() == wxTRANSPARENT) + { + wxLogDebug(wxT("In FloodFill, current Brush is transparent, no filling done")); + return ; + } + int height = 0; + int width = 0; + this->GetSize(&width, &height); + //it would be nice to fail if we don't get a sensible size... + if (width < 1 || height < 1) + { + wxLogError(wxT("In FloodFill, dc.GetSize routine failed, method not supported by this DC")); + return ; + } + + //this is much faster than doing the individual pixels + wxMemoryDC memdc; + wxBitmap bitmap(width, height); + memdc.SelectObject(bitmap); + memdc.Blit(0, 0, width, height, (wxDC*) this, 0, 0); + memdc.SelectObject(wxNullBitmap); + + wxImage image(bitmap); + image.DoFloodFill (x,y, GetBrush(), col, style, GetLogicalFunction()); + bitmap = wxBitmap(image); + memdc.SelectObject(bitmap); + this->Blit(0, 0, width, height, &memdc, 0, 0); + memdc.SelectObject(wxNullBitmap); } bool wxWindowDC::DoGetPixel( wxCoord x1, wxCoord y1, wxColour *col ) const diff --git a/src/mac/carbon/dc.cpp b/src/mac/carbon/dc.cpp index f44f47270f..2828b715c6 100644 --- a/src/mac/carbon/dc.cpp +++ b/src/mac/carbon/dc.cpp @@ -19,6 +19,7 @@ #include "wx/dcmemory.h" #include "wx/region.h" #include "wx/image.h" +#include "wx/log.h" #if __MSL__ >= 0x6000 @@ -653,6 +654,34 @@ void wxDC::DoFloodFill( wxCoord x, wxCoord y, const wxColour& col, { } + if (GetBrush().GetStyle() == wxTRANSPARENT) + { + wxLogDebug(wxT("In FloodFill, Current Brush is transparent, no filling done")); + return ; + } + int height = 0; + int width = 0; + this->GetSize(&width, &height); + //it would be nice to fail if we don't get a sensible size... + if (width < 1 || height < 1) + { + wxLogError(wxT("In FloodFill, dc.GetSize routine failed, method not supported by this DC")); + return ; + } + + //this is much faster than doing the individual pixels + wxMemoryDC memdc; + wxBitmap bitmap(width, height); + memdc.SelectObject(bitmap); + memdc.Blit(0, 0, width, height, (wxDC*) this, 0, 0); + memdc.SelectObject(wxNullBitmap); + + wxImage image(bitmap); + image.DoFloodFill (x,y, GetBrush(), col, style, GetLogicalFunction()); + bitmap = wxBitmap(image); + memdc.SelectObject(bitmap); + this->Blit(0, 0, width, height, &memdc, 0, 0); + memdc.SelectObject(wxNullBitmap); bool wxDC::DoGetPixel( wxCoord x, wxCoord y, wxColour *col ) const { wxCHECK_MSG( Ok(), false, wxT("wxDC::DoGetPixel Invalid DC") ); diff --git a/src/mac/dc.cpp b/src/mac/dc.cpp index f44f47270f..2828b715c6 100644 --- a/src/mac/dc.cpp +++ b/src/mac/dc.cpp @@ -19,6 +19,7 @@ #include "wx/dcmemory.h" #include "wx/region.h" #include "wx/image.h" +#include "wx/log.h" #if __MSL__ >= 0x6000 @@ -653,6 +654,34 @@ void wxDC::DoFloodFill( wxCoord x, wxCoord y, const wxColour& col, { } + if (GetBrush().GetStyle() == wxTRANSPARENT) + { + wxLogDebug(wxT("In FloodFill, Current Brush is transparent, no filling done")); + return ; + } + int height = 0; + int width = 0; + this->GetSize(&width, &height); + //it would be nice to fail if we don't get a sensible size... + if (width < 1 || height < 1) + { + wxLogError(wxT("In FloodFill, dc.GetSize routine failed, method not supported by this DC")); + return ; + } + + //this is much faster than doing the individual pixels + wxMemoryDC memdc; + wxBitmap bitmap(width, height); + memdc.SelectObject(bitmap); + memdc.Blit(0, 0, width, height, (wxDC*) this, 0, 0); + memdc.SelectObject(wxNullBitmap); + + wxImage image(bitmap); + image.DoFloodFill (x,y, GetBrush(), col, style, GetLogicalFunction()); + bitmap = wxBitmap(image); + memdc.SelectObject(bitmap); + this->Blit(0, 0, width, height, &memdc, 0, 0); + memdc.SelectObject(wxNullBitmap); bool wxDC::DoGetPixel( wxCoord x, wxCoord y, wxColour *col ) const { wxCHECK_MSG( Ok(), false, wxT("wxDC::DoGetPixel Invalid DC") ); diff --git a/src/mgl/dc.cpp b/src/mgl/dc.cpp index 60d8043928..e38597f419 100644 --- a/src/mgl/dc.cpp +++ b/src/mgl/dc.cpp @@ -334,7 +334,34 @@ void wxDC::Clear() void wxDC::DoFloodFill(wxCoord x, wxCoord y, const wxColour& col, int style) { - wxFAIL_MSG( wxT("wxDC::DoFloodFill not implemented") ); + if (GetBrush().GetStyle() == wxTRANSPARENT) + { + wxLogDebug(wxT("In FloodFill, Current Brush is transparent, no filling done")); + return ; + } + int height = 0; + int width = 0; + this->GetSize(&width, &height); + //it would be nice to fail if we don't get a sensible size... + if (width < 1 || height < 1) + { + wxLogError(wxT("In FloodFill, dc.GetSize routine failed, method not supported by this DC")); + return ; + } + + //this is much faster than doing the individual pixels + wxMemoryDC memdc; + wxBitmap bitmap(width, height); + memdc.SelectObject(bitmap); + memdc.Blit(0, 0, width, height, (wxDC*) this, 0, 0); + memdc.SelectObject(wxNullBitmap); + + wxImage image(bitmap); + image.DoFloodFill (x,y, GetBrush(), col, style, GetLogicalFunction()); + bitmap = wxBitmap(image); + memdc.SelectObject(bitmap); + this->Blit(0, 0, width, height, &memdc, 0, 0); + memdc.SelectObject(wxNullBitmap); } bool wxDC::DoGetPixel(wxCoord x, wxCoord y, wxColour *col) const diff --git a/src/motif/dcclient.cpp b/src/motif/dcclient.cpp index f442f9ebca..e9d28fdb10 100644 --- a/src/motif/dcclient.cpp +++ b/src/motif/dcclient.cpp @@ -45,6 +45,7 @@ #include "wx/window.h" #include "wx/app.h" #include "wx/image.h" +#include "wx/log.h" #include @@ -230,12 +231,39 @@ wxWindowDC::~wxWindowDC() m_userRegion = (WXRegion) 0; } -void wxWindowDC::DoFloodFill( wxCoord WXUNUSED(x1), wxCoord WXUNUSED(y1), - const wxColour& WXUNUSED(col), int WXUNUSED(style) ) +void wxWindowDC::DoFloodFill( wxCoord x1, wxCoord y1, + const wxColour& col, int style ) { - wxFAIL_MSG("not implemented"); -} + if (GetBrush().GetStyle() == wxTRANSPARENT) + { + wxLogDebug(wxT("In FloodFill, current brush is transparent, no filling done")); + return ; + } + int height = 0; + int width = 0; + this->GetSize(&width, &height); + //it would be nice to fail if we don't get a sensible size... + if (width < 1 || height < 1) + { + wxLogError(wxT("In FloodFill, dc.GetSize routine failed, method not supported by this DC")); + return ; + } + //this is much faster than doing the individual pixels + wxMemoryDC memdc; + wxBitmap bitmap(width, height); + memdc.SelectObject(bitmap); + memdc.Blit(0, 0, width, height, (wxDC*) this, 0, 0); + memdc.SelectObject(wxNullBitmap); + + wxImage image(bitmap); + image.DoFloodFill (x,y, GetBrush(), col, style, GetLogicalFunction()); + bitmap = wxBitmap(image); + memdc.SelectObject(bitmap); + this->Blit(0, 0, width, height, &memdc, 0, 0); + memdc.SelectObject(wxNullBitmap); +} + bool wxWindowDC::DoGetPixel( wxCoord x1, wxCoord y1, wxColour *col ) const { // Generic (and therefore rather inefficient) method. diff --git a/src/x11/dcclient.cpp b/src/x11/dcclient.cpp index 659feec8ae..13cfe8ad9a 100644 --- a/src/x11/dcclient.cpp +++ b/src/x11/dcclient.cpp @@ -313,10 +313,37 @@ void wxWindowDC::DoGetSize( int* width, int* height ) const m_owner->GetSize(width, height); } -void wxWindowDC::DoFloodFill( wxCoord WXUNUSED(x1), wxCoord WXUNUSED(y1), - const wxColour& WXUNUSED(col), int WXUNUSED(style) ) +void wxWindowDC::DoFloodFill( wxCoord x, wxCoord y, + const wxColour & col, int style ) { - wxFAIL_MSG("not implemented"); + if (GetBrush().GetStyle() == wxTRANSPARENT) + { + wxLogDebug(wxT("In FloodFill, current brush is transparent, no filling done")); + return ; + } + int height = 0; + int width = 0; + this->GetSize(&width, &height); + //it would be nice to fail if we don't get a sensible size... + if (width < 1 || height < 1) + { + wxLogError(wxT("In FloodFill, dc.GetSize routine failed, method not supported by this DC")); + return ; + } + + //this is much faster than doing the individual pixels + wxMemoryDC memdc; + wxBitmap bitmap(width, height); + memdc.SelectObject(bitmap); + memdc.Blit(0, 0, width, height, (wxDC*) this, 0, 0); + memdc.SelectObject(wxNullBitmap); + + wxImage image(bitmap); + image.DoFloodFill (x,y, GetBrush(), col, style, GetLogicalFunction()); + bitmap = wxBitmap(image); + memdc.SelectObject(bitmap); + this->Blit(0, 0, width, height, &memdc, 0, 0); + memdc.SelectObject(wxNullBitmap); } bool wxWindowDC::DoGetPixel( wxCoord x1, wxCoord y1, wxColour *col ) const