]> git.saurik.com Git - wxWidgets.git/blame - src/common/imagfill.cpp
GTK2: gtk_idle_add_priority -> g_idle_add_full; gtk_idle_remove -> g_source_remove
[wxWidgets.git] / src / common / imagfill.cpp
CommitLineData
7011cf13
JS
1/////////////////////////////////////////////////////////////////////////////
2// Name: imagfill.cpp
3// Purpose: FloodFill for wxImage
99d80019 4// Author: Julian Smart
7011cf13 5// RCS-ID: $Id$
99d80019 6// Copyright: (c) Julian Smart
65571936 7// Licence: wxWindows licence
7011cf13
JS
8/////////////////////////////////////////////////////////////////////////////
9
7011cf13
JS
10
11// For compilers that support precompilation, includes "wx.h".
12#include "wx/wxprec.h"
13
14#ifdef __BORLANDC__
15 #pragma hdrstop
16#endif
17
3a0a5ada
VS
18#include "wx/defs.h"
19
20#if wxUSE_IMAGE && !defined(__WXMSW__)
21// we have no use for this code in wxMSW...
7011cf13
JS
22
23#include "wx/image.h"
0fc5dbf5
VZ
24
25#ifndef WX_PRECOMP
26 #include "wx/brush.h"
3a0a5ada
VS
27 #include "wx/dc.h"
28 #include "wx/dcmemory.h"
0fc5dbf5 29#endif
7011cf13
JS
30
31// DoFloodFill
32// Fills with the colour extracted from fillBrush, starting at x,y until either
33// a color different from the start pixel is reached (wxFLOOD_SURFACE)
34// or fill color is reached (wxFLOOD_BORDER)
35
f5f05abf 36static bool LINKAGEMODE MatchPixel(wxImage *img, int x, int y, int w, int h, const wxColour& c)
7011cf13 37{
7beb59f3 38 if ((x<0)||(x>=w)||(y<0)||(y>=h)) return false;
7011cf13 39
3a0a5ada
VS
40 unsigned char r = img->GetRed(x,y);
41 unsigned char g = img->GetGreen(x,y);
42 unsigned char b = img->GetBlue(x,y);
7011cf13
JS
43 return c.Red() == r && c.Green() == g && c.Blue() == b ;
44}
45
f5f05abf 46static bool LINKAGEMODE MatchBoundaryPixel(wxImage *img, int x, int y, int w, int h, const wxColour & fill, const wxColour& bound)
7011cf13 47{
7beb59f3 48 if ((x<0)||(x>=w)||(y<0)||(y>=h)) return true;
7011cf13 49
3a0a5ada
VS
50 unsigned char r = img->GetRed(x,y);
51 unsigned char g = img->GetGreen(x,y);
52 unsigned char b = img->GetBlue(x,y);
f5f05abf 53 if ( fill.Red() == r && fill.Green() == g && fill.Blue() == b )
7beb59f3 54 return true;
f5f05abf 55 if ( bound.Red() == r && bound.Green() == g && bound.Blue() == b )
7beb59f3
WS
56 return true;
57 return false;
7011cf13
JS
58}
59
60
f5f05abf
DW
61static void LINKAGEMODE
62wxImageFloodFill(wxImage *image,
63 wxCoord x, wxCoord y, const wxBrush & fillBrush,
64 const wxColour& testColour, int style,
7a893a31 65 int WXUNUSED(LogicalFunction))
7011cf13
JS
66{
67 /* A diamond flood-fill using a circular queue system.
68 Each pixel surrounding the current pixel is added to
69 the queue if it meets the criteria, then is retrieved in
068993c7
JS
70 its turn. Code originally based on http://www.drawit.co.nz/Developers.htm,
71 with explicit permission to use this for wxWidgets granted by Andrew Empson
72 (no copyright claimed)
73 */
7011cf13 74
3a0a5ada
VS
75 int width = image->GetWidth();
76 int height = image->GetHeight();
7011cf13
JS
77
78 //Draw using a pen made from the current brush colour
79 //Potentially allows us to use patterned flood fills in future code
80 wxColour fillColour = fillBrush.GetColour();
81 unsigned char r = fillColour.Red();
82 unsigned char g = fillColour.Green();
83 unsigned char b = fillColour.Blue();
84
85 //initial test :
86 if (style == wxFLOOD_SURFACE)
87 {
88 //if wxFLOOD_SURFACE, if fill colour is same as required, we don't do anything
3a0a5ada
VS
89 if ( image->GetRed(x,y) != r
90 || image->GetGreen(x,y) != g
91 || image->GetBlue (x,y) != b )
7011cf13
JS
92 {
93 //prepare memory for queue
94 //queue save, start, read
95 size_t *qs, *qst, *qr;
96
97 //queue size (physical)
98 long qSz= height * width * 2;
99 qst = new size_t [qSz];
100
101 //temporary x and y locations
102 int xt, yt;
103
104 for (int i=0; i < qSz; i++)
105 qst[i] = 0;
106
107 // start queue
108 qs=qr=qst;
109 *qs=xt=x;
110 qs++;
111 *qs=yt=y;
112 qs++;
113
3a0a5ada 114 image->SetRGB(xt,yt,r,g,b);
7011cf13
JS
115
116 //Main queue loop
117 while(qr!=qs)
118 {
119 //Add new members to queue
120 //Above current pixel
3a0a5ada 121 if(MatchPixel(image,xt,yt-1,width,height,testColour))
7011cf13
JS
122 {
123 *qs=xt;
124 qs++;
125 *qs=yt-1;
126 qs++;
3a0a5ada 127 image->SetRGB(xt,yt-1,r,g,b);
7011cf13
JS
128
129 //Loop back to beginning of queue
130 if(qs>=(qst+qSz)) qs=qst;
131 }
132
133 //Below current pixel
3a0a5ada 134 if(MatchPixel(image,xt,yt+1,width,height,testColour))
7011cf13
JS
135 {
136 *qs=xt;
137 qs++;
138 *qs=yt+1;
139 qs++;
3a0a5ada 140 image->SetRGB(xt,yt+1,r,g,b);
7011cf13
JS
141 if(qs>=(qst+qSz)) qs=qst;
142 }
143
144 //Left of current pixel
3a0a5ada 145 if(MatchPixel(image,xt-1,yt,width,height,testColour))
7011cf13
JS
146 {
147 *qs=xt-1;
148 qs++;
149 *qs=yt;
150 qs++;
3a0a5ada 151 image->SetRGB(xt-1,yt,r,g,b);
7011cf13
JS
152 if(qs>=(qst+qSz)) qs=qst;
153 }
154
155 //Right of current pixel
3a0a5ada 156 if(MatchPixel(image,xt+1,yt,width,height,testColour))
7011cf13
JS
157 {
158 *qs=xt+1;
159 qs++;
160 *qs=yt;
161 qs++;
3a0a5ada 162 image->SetRGB(xt+1,yt,r,g,b);
7011cf13
JS
163 if(qs>=(qst+qSz)) qs=qst;
164 }
165
166 //Retrieve current queue member
167 qr+=2;
168
169 //Loop back to the beginning
170 if(qr>=(qst+qSz)) qr=qst;
171 xt=*qr;
172 yt=*(qr+1);
173
174 //Go Back to beginning of loop
175 }
176
3a0a5ada 177 delete[] qst;
7011cf13
JS
178 }
179 }
180 else
181 {
182 //style is wxFLOOD_BORDER
183 // fill up to testColor border - if already testColour don't do anything
3a0a5ada
VS
184 if ( image->GetRed(x,y) != testColour.Red()
185 || image->GetGreen(x,y) != testColour.Green()
186 || image->GetBlue(x,y) != testColour.Blue() )
187 {
7011cf13
JS
188 //prepare memory for queue
189 //queue save, start, read
190 size_t *qs, *qst, *qr;
191
192 //queue size (physical)
193 long qSz= height * width * 2;
194 qst = new size_t [qSz];
195
196 //temporary x and y locations
197 int xt, yt;
198
199 for (int i=0; i < qSz; i++)
200 qst[i] = 0;
201
202 // start queue
203 qs=qr=qst;
204 *qs=xt=x;
205 qs++;
206 *qs=yt=y;
207 qs++;
208
3a0a5ada 209 image->SetRGB(xt,yt,r,g,b);
7011cf13
JS
210
211 //Main queue loop
3a0a5ada 212 while (qr!=qs)
7011cf13
JS
213 {
214 //Add new members to queue
215 //Above current pixel
3a0a5ada 216 if(!MatchBoundaryPixel(image,xt,yt-1,width,height,fillColour,testColour))
7011cf13
JS
217 {
218 *qs=xt;
219 qs++;
220 *qs=yt-1;
221 qs++;
3a0a5ada 222 image->SetRGB(xt,yt-1,r,g,b);
7011cf13
JS
223
224 //Loop back to beginning of queue
225 if(qs>=(qst+qSz)) qs=qst;
226 }
227
228 //Below current pixel
3a0a5ada 229 if(!MatchBoundaryPixel(image,xt,yt+1,width,height,fillColour,testColour))
7011cf13
JS
230 {
231 *qs=xt;
232 qs++;
233 *qs=yt+1;
234 qs++;
3a0a5ada 235 image->SetRGB(xt,yt+1,r,g,b);
7011cf13
JS
236 if(qs>=(qst+qSz)) qs=qst;
237 }
238
239 //Left of current pixel
3a0a5ada 240 if(!MatchBoundaryPixel(image,xt-1,yt,width,height,fillColour,testColour))
7011cf13
JS
241 {
242 *qs=xt-1;
243 qs++;
244 *qs=yt;
245 qs++;
3a0a5ada 246 image->SetRGB(xt-1,yt,r,g,b);
7011cf13
JS
247 if(qs>=(qst+qSz)) qs=qst;
248 }
249
250 //Right of current pixel
3a0a5ada 251 if(!MatchBoundaryPixel(image,xt+1,yt,width,height,fillColour,testColour))
7011cf13
JS
252 {
253 *qs=xt+1;
254 qs++;
255 *qs=yt;
256 qs++;
3a0a5ada 257 image->SetRGB(xt+1,yt,r,g,b);
7011cf13
JS
258 if(qs>=(qst+qSz)) qs=qst;
259 }
260
261 //Retrieve current queue member
262 qr+=2;
263
264 //Loop back to the beginning
265 if(qr>=(qst+qSz)) qr=qst;
266 xt=*qr;
267 yt=*(qr+1);
268
269 //Go Back to beginning of loop
270 }
271
3a0a5ada 272 delete[] qst;
7011cf13
JS
273 }
274 }
275 //all done,
276}
277
3a0a5ada 278
f842e673
KH
279bool wxDoFloodFill(wxDC *dc, wxCoord x, wxCoord y,
280 const wxColour& col, int style)
281{
282 if (dc->GetBrush().GetStyle() == wxTRANSPARENT)
283 return true;
7011cf13 284
f842e673
KH
285 int height = 0;
286 int width = 0;
287 dc->GetSize(&width, &height);
288
289 //it would be nice to fail if we don't get a sensible size...
290 wxCHECK_MSG(width >= 1 && height >= 1, false,
291 wxT("In FloodFill, dc.GetSize routine failed, method not supported by this DC"));
292
293 //this is much faster than doing the individual pixels
294 wxMemoryDC memdc;
295 wxBitmap bitmap(width, height);
296 memdc.SelectObject(bitmap);
297 memdc.Blit(0, 0, width, height, dc, 0, 0);
298 memdc.SelectObject(wxNullBitmap);
299
300 wxImage image = bitmap.ConvertToImage();
301 wxImageFloodFill(&image, x,y, dc->GetBrush(), col, style,
302 dc->GetLogicalFunction());
303 bitmap = wxBitmap(image);
304 memdc.SelectObject(bitmap);
305 dc->Blit(0, 0, width, height, &memdc, 0, 0);
306 memdc.SelectObject(wxNullBitmap);
307
308 return true;
309}
310
311#endif // wxUSE_IMAGE