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