Bug Summary

File:home/HaikuArchives/ArtPaint/artpaint/tools/FillTool.cpp
Warning:line 1235, column 3
Value stored to 'x_accumulation' is never read

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-unknown-haiku -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name FillTool.cpp -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model static -mframe-pointer=all -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -tune-cpu generic -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /boot/system/lib/clang/12.0.1 -iquote ./ -iquote artpaint/ -iquote artpaint/Utilities/ -iquote artpaint/application/ -iquote artpaint/controls/ -iquote artpaint/layers/ -iquote artpaint/paintwindow/ -iquote artpaint/tools/ -iquote artpaint/viewmanipulators/ -iquote artpaint/windows/ -iquote objects_artpaint/ -isystem /boot/system/develop/headers/private/interface -internal-isystem /system/develop/headers/c++ -internal-isystem /system/develop/headers/c++/x86_64-unknown-haiku -internal-isystem /system/develop/headers/c++/backward -O3 -fdeprecated-macro -fdebug-compilation-dir /boot/home/HaikuArchives/ArtPaint -ferror-limit 19 -fgnuc-version=4.2.1 -fcxx-exceptions -fexceptions -vectorize-loops -vectorize-slp -analyzer-output=html -faddrsig -o /tmp/scan-build-2022-06-19-103017-1294-1 -x c++ artpaint/tools/FillTool.cpp
1/*
2 * Copyright 2003, Heikki Suhonen
3 * Copyright 2009, Karsten Heimrich
4 * Distributed under the terms of the MIT License.
5 *
6 * Authors:
7 * Heikki Suhonen <heikki.suhonen@gmail.com>
8 * Karsten Heimrich <host.haiku@gmx.de>
9 * Dale Cieslak <dcieslak@yahoo.com>
10 *
11 */
12
13#include "FillTool.h"
14
15#include "BitmapDrawer.h"
16#include "ColorPalette.h"
17#include "ColorView.h"
18#include "Cursors.h"
19#include "Image.h"
20#include "ImageView.h"
21#include "NumberSliderControl.h"
22#include "PaintApplication.h"
23#include "PixelOperations.h"
24#include "Selection.h"
25#include "ToolScript.h"
26#include "UtilityClasses.h"
27
28
29#include <Catalog.h>
30#include <CheckBox.h>
31#include <Control.h>
32#include <File.h>
33#include <GridLayoutBuilder.h>
34#include <GroupLayoutBuilder.h>
35#include <SeparatorView.h>
36
37
38#include <stdlib.h>
39#include <string.h>
40
41
42#undef B_TRANSLATION_CONTEXT"Tools"
43#define B_TRANSLATION_CONTEXT"Tools" "Tools"
44
45
46using ArtPaint::Interface::NumberSliderControl;
47
48
49FillTool::FillTool()
50 : DrawingTool(B_TRANSLATE("Fill tool")BLocaleRoster::Default()->GetCatalog()->GetString(("Fill tool"
), "Tools")
, FILL_TOOL)
51{
52 // Set options here. The MODE_OPTION is used for determining if we do flood
53 // fill or some other type of fill.
54 fOptions = GRADIENT_ENABLED_OPTION | PREVIEW_ENABLED_OPTION
55 | TOLERANCE_OPTION | MODE_OPTION;
56 fOptionsCount = 4;
57 binary_fill_map = NULL__null;
58
59 // Initially disable the gradient.
60 SetOption(GRADIENT_ENABLED_OPTION, B_CONTROL_OFF);
61 // Initially enable the preview.
62 SetOption(PREVIEW_ENABLED_OPTION,B_CONTROL_ON);
63 SetOption(TOLERANCE_OPTION,0);
64 SetOption(MODE_OPTION,B_CONTROL_ON);
65
66 gradient_color1 = 0x00000000;
67 gradient_color2 = 0xFFFFFFFF;
68}
69
70
71FillTool::~FillTool()
72{
73}
74
75
76ToolScript*
77FillTool::UseTool(ImageView *view, uint32 buttons, BPoint point, BPoint viewPoint)
78{
79 ToolScript* toolScript = new ToolScript(Type(), fToolSettings,
80 ((PaintApplication*)be_app)->Color(true));
81 toolScript->AddPoint(point);
82
83 Selection* selection = view->GetSelection();
84 selection = (selection->IsEmpty() ? NULL__null : selection);
85
86 if (fToolSettings.gradient_enabled == B_CONTROL_ON) {
87 // Do just a fill with gradient
88 toolScript->AddPoint(GradientFill(view, buttons, point, viewPoint,
89 selection));
90 } else {
91 // Do just a normal fill without gradient
92 NormalFill(view, buttons, point, selection);
93 }
94
95 return toolScript;
96}
97
98
99int32
100FillTool::UseToolWithScript(ToolScript*, BBitmap*)
101{
102 return B_OK((int)0);
103}
104
105
106BView*
107FillTool::ConfigView()
108{
109 return new FillToolConfigView(this, gradient_color1, gradient_color2);
110}
111
112
113status_t
114FillTool::NormalFill(ImageView* view, uint32 buttons, BPoint start, Selection* sel)
115{
116 // Get the necessary parameters
117 BWindow *window = view->Window();
118 if (window == NULL__null)
119 return B_ERROR(-1);
120
121 uint32 tolerance = (uint32)((float)fToolSettings.tolerance/100.0 * 255);
122
123 filled_bitmap = view->ReturnImage()->ReturnActiveBitmap();
124 BitmapDrawer *drawer = new BitmapDrawer(filled_bitmap);
125 BRect bitmap_bounds = filled_bitmap->Bounds();
126 bitmap_bounds.OffsetTo(BPoint(0,0));
127
128 // Get the color for the fill.
129 rgb_color c = ((PaintApplication*)be_app)->Color(TRUE1);
130 uint32 color = RGBColorToBGRA(c);
131
132 // Get the old color.
133 uint32 old_color = drawer->GetPixel(start);
134
135 // If the old color is the same as new and the tolerance is 0, we should do nothing.
136 if ( (old_color == color) && (tolerance == 0) ) {
137 delete drawer;
138 return B_OK((int)0);
139 }
140
141 // These are the edge coordinates of bitmap. It is still safe to
142 // address a pixel at max_x,max_y or min_x,min_y.
143 int32 min_x,min_y,max_x,max_y;
144 min_x = (int32)bitmap_bounds.left;
145 min_y = (int32)bitmap_bounds.top;
146 max_x = (int32)bitmap_bounds.right;
147 max_y = (int32)bitmap_bounds.bottom;
148
149 if (bitmap_bounds.Contains(start) == TRUE1) {
150 if (fToolSettings.mode == B_CONTROL_ON) { // Do the flood fill
151 // Here fill the area using drawer's SetPixel and GetPixel.
152 // The algorithm uses 4-connected version of flood-fill.
153 // The SetPixel and GetPixel functions are versions that
154 // do not check bounds so we have to be careful not to exceed
155 // bitmap's bounds.
156 if (tolerance != 0) {
157 binary_fill_map = new BBitmap(filled_bitmap->Bounds(), B_GRAY1);
158 // Clear the binary map.
159 uchar *binary_bits = (uchar*)binary_fill_map->Bits();
160 uint32 binary_bitslength = binary_fill_map->BitsLength();
161 for (uint32 i = 0; i < binary_bitslength; i++)
162 *binary_bits++ = 0x00;
163 }
164
165 PointStack stack;
166 stack.Push(start);
167
168 while (!stack.IsEmpty()) {
169 BPoint span_start = stack.Pop();
170 if ( (span_start.y == min_y) && (min_y != max_y) ) {
171 // Only check the spans below this line
172 CheckLowerSpans(span_start, drawer, stack, min_x, max_x,
173 color, old_color, tolerance, sel);
174 }
175 else if ( (span_start.y == max_y) && (min_y != max_y) ) {
176 // Only check the spans above this line.
177 CheckUpperSpans(span_start, drawer, stack, min_x, max_x,
178 color, old_color, tolerance, sel);
179 }
180 else if (min_y != max_y) {
181 // Check the spans above and below this line.
182 CheckBothSpans(span_start, drawer, stack, min_x, max_x,
183 color, old_color, tolerance, sel);
184 }
185 else {
186 // The image is only one pixel high. Fill the only span.
187 FillSpan(span_start, drawer, min_x, max_x, color, old_color,
188 tolerance, sel);
189 }
190 }
191 if (tolerance != 0) {
192 delete binary_fill_map;
193 binary_fill_map = NULL__null;
194 }
195 }
196 else { // Fill all the pixels that are within the tolerance.
197 if ((sel == NULL__null) || (sel->IsEmpty() == true)) {
198 for (int32 y=min_y;y<=max_y;y++) {
199 for (int32 x=min_x;x<=max_x;x++) {
200 if (compare_2_pixels_with_variance(old_color,drawer->GetPixel(x,y),tolerance)) {
201 drawer->SetPixel(x,y,color);
202 }
203 }
204 }
205 }
206 else {
207 for (int32 y=min_y;y<=max_y;y++) {
208 for (int32 x=min_x;x<=max_x;x++) {
209 if (sel->ContainsPoint(x,y) && compare_2_pixels_with_variance(old_color,drawer->GetPixel(x,y),tolerance)) {
210 drawer->SetPixel(x,y,color);
211 }
212 }
213 }
214 }
215 }
216
217 SetLastUpdatedRect(filled_bitmap->Bounds());
218 window->Lock();
219 view->UpdateImage(LastUpdatedRect());
220 view->Sync();
221 window->Unlock();
222 }
223 delete drawer;
224 return B_OK((int)0);
225}
226
227
228void
229FillTool::CheckLowerSpans(BPoint span_start,BitmapDrawer *drawer,PointStack &stack,int32 min_x,int32 max_x,uint32 new_color,uint32 old_color,int32 tolerance,Selection *sel)
230{
231 // First get the vital data.
232 int32 x,start_x;
233 int32 y = (int32)span_start.y;
234 x = start_x = (int32)span_start.x;
235 bool inside_lower_span = FALSE0;
236
237 if ((sel == NULL__null) || (sel->IsEmpty() == TRUE1)) {
238 if ((tolerance == 0) && (binary_fill_map == NULL__null)) {
239 // Then go from start towards the left side of the bitmap.
240 while ( (x >= min_x) && (drawer->GetPixel(x,y) == old_color) ) {
241 drawer->SetPixel(x,y,new_color);
242 if ( (inside_lower_span == FALSE0) && (drawer->GetPixel(x,y+1) == old_color) ) {
243 stack.Push(BPoint(x,y+1));
244 inside_lower_span = TRUE1;
245 }
246 else if ( (inside_lower_span == TRUE1) && (drawer->GetPixel(x,y+1) != old_color) ) {
247 inside_lower_span = FALSE0;
248 }
249 x--;
250 }
251
252 // Then go from start_x+1 towards the right side of the bitmap.
253 // We might already be inside a lower span
254 inside_lower_span = ( drawer->GetPixel(start_x,y+1) == old_color );
255 x = start_x + 1;
256 while ( (x <= max_x) && (drawer->GetPixel(x,y) == old_color) ) {
257 drawer->SetPixel(x,y,new_color);
258 if ( (inside_lower_span == FALSE0) && (drawer->GetPixel(x,y+1) == old_color) ) {
259 stack.Push(BPoint(x,y+1));
260 inside_lower_span = TRUE1;
261 }
262 else if ( (inside_lower_span == TRUE1) && (drawer->GetPixel(x,y+1) != old_color) ) {
263 inside_lower_span = FALSE0;
264 }
265 x++;
266 }
267 }
268 else {
269 // This is the case that takes the variance into account. We must use a
270 // binary bitmap to see what parts have already been filled.
271 uint32 binary_bpr = binary_fill_map->BytesPerRow();
272 uchar *binary_bits = (uchar*)binary_fill_map->Bits();
273 // Then go from start towards the left side of the bitmap.
274 while ( (x >= min_x) && (compare_2_pixels_with_variance(drawer->GetPixel(x,y),old_color,tolerance)) && ((*(binary_bits + y*binary_bpr + (x/8))&(0x01 << (7-x%8))) == 0x00) ) {
275 drawer->SetPixel(x,y,new_color);
276 // *(binary_bits + y*binary_bpr + (x/8)) = *(binary_bits + y*binary_bpr + (x/8)) | (0x01 << (7 - x%8));
277 *(binary_bits + y*binary_bpr + (x/8)) |= (0x01 << (7 - x%8));
278 if ( (inside_lower_span == FALSE0) && (compare_2_pixels_with_variance(drawer->GetPixel(x,y+1),old_color,tolerance)) ) {
279 stack.Push(BPoint(x,y+1));
280 inside_lower_span = TRUE1;
281 }
282 else if ( (inside_lower_span == TRUE1) && (!compare_2_pixels_with_variance(drawer->GetPixel(x,y+1),old_color,tolerance)) ) {
283 inside_lower_span = FALSE0;
284 }
285 x--;
286 }
287
288 // Then go from start_x+1 towards the right side of the bitmap.
289 // We might already be inside a lower span
290 inside_lower_span = ( compare_2_pixels_with_variance(drawer->GetPixel(start_x,y+1),old_color,tolerance) );
291 x = start_x + 1;
292 while ( (x <= max_x) && (compare_2_pixels_with_variance(drawer->GetPixel(x,y),old_color,tolerance)) && ((*(binary_bits + y*binary_bpr + (x/8))&(0x01 << (7-x%8))) == 0x00) ) {
293 drawer->SetPixel(x,y,new_color);
294 // *(binary_bits + y*binary_bpr + (x/8)) = *(binary_bits + y*binary_bpr + (x/8)) | (0x01 << (7 - x%8));
295 *(binary_bits + y*binary_bpr + (x/8)) |= (0x01 << (7 - x%8));
296 if ( (inside_lower_span == FALSE0) && (compare_2_pixels_with_variance(drawer->GetPixel(x,y+1),old_color,tolerance)) ) {
297 stack.Push(BPoint(x,y+1));
298 inside_lower_span = TRUE1;
299 }
300 else if ( (inside_lower_span == TRUE1) && (!compare_2_pixels_with_variance(drawer->GetPixel(x,y+1),old_color,tolerance)) ) {
301 inside_lower_span = FALSE0;
302 }
303 x++;
304 }
305 }
306 }
307 else {
308 if ((tolerance == 0) && (binary_fill_map == NULL__null)) {
309 // Then go from start towards the left side of the bitmap.
310 while (sel->ContainsPoint(x,y) && (x >= min_x) && (drawer->GetPixel(x,y) == old_color) ) {
311 drawer->SetPixel(x,y,new_color);
312 if ( (inside_lower_span == FALSE0) && (drawer->GetPixel(x,y+1) == old_color) && sel->ContainsPoint(x,y+1)) {
313 stack.Push(BPoint(x,y+1));
314 inside_lower_span = TRUE1;
315 }
316 else if ( (inside_lower_span == TRUE1) && ((drawer->GetPixel(x,y+1) != old_color) || !sel->ContainsPoint(x,y+1))) {
317 inside_lower_span = FALSE0;
318 }
319 x--;
320 }
321
322 // Then go from start_x+1 towards the right side of the bitmap.
323 // We might already be inside a lower span
324 inside_lower_span = ( drawer->GetPixel(start_x,y+1) == old_color ) && sel->ContainsPoint(start_x,y+1);
325 x = start_x + 1;
326 while (sel->ContainsPoint(x,y) && (x <= max_x) && (drawer->GetPixel(x,y) == old_color) ) {
327 drawer->SetPixel(x,y,new_color);
328 if ( (inside_lower_span == FALSE0) && (drawer->GetPixel(x,y+1) == old_color) && sel->ContainsPoint(x,y+1)) {
329 stack.Push(BPoint(x,y+1));
330 inside_lower_span = TRUE1;
331 }
332 else if ( (inside_lower_span == TRUE1) && ((drawer->GetPixel(x,y+1) != old_color) || !sel->ContainsPoint(x,y+1))) {
333 inside_lower_span = FALSE0;
334 }
335 x++;
336 }
337 }
338 else {
339 // This is the case that takes the variance into account. We must use a
340 // binary bitmap to see what parts have already been filled.
341 uint32 binary_bpr = binary_fill_map->BytesPerRow();
342 uchar *binary_bits = (uchar*)binary_fill_map->Bits();
343 // Then go from start towards the left side of the bitmap.
344 while (sel->ContainsPoint(x,y) && (x >= min_x) && (compare_2_pixels_with_variance(drawer->GetPixel(x,y),old_color,tolerance)) && ((*(binary_bits + y*binary_bpr + (x/8))&(0x01 << (7-x%8))) == 0x00) ) {
345 drawer->SetPixel(x,y,new_color);
346 *(binary_bits + y*binary_bpr + (x/8)) |= (0x01 << (7 - x%8));
347 if ( (inside_lower_span == FALSE0) && (compare_2_pixels_with_variance(drawer->GetPixel(x,y+1),old_color,tolerance)) && sel->ContainsPoint(x,y+1) ) {
348 stack.Push(BPoint(x,y+1));
349 inside_lower_span = TRUE1;
350 }
351 else if ( (inside_lower_span == TRUE1) && (!compare_2_pixels_with_variance(drawer->GetPixel(x,y+1),old_color,tolerance) || !sel->ContainsPoint(x,y+1)) ) {
352 inside_lower_span = FALSE0;
353 }
354 x--;
355 }
356
357 // Then go from start_x+1 towards the right side of the bitmap.
358 // We might already be inside a lower span
359 inside_lower_span = ( compare_2_pixels_with_variance(drawer->GetPixel(start_x,y+1),old_color,tolerance) && sel->ContainsPoint(start_x,y+1));
360 x = start_x + 1;
361 while (sel->ContainsPoint(x,y) && (x <= max_x) && (compare_2_pixels_with_variance(drawer->GetPixel(x,y),old_color,tolerance)) && ((*(binary_bits + y*binary_bpr + (x/8))&(0x01 << (7-x%8))) == 0x00) ) {
362 drawer->SetPixel(x,y,new_color);
363 *(binary_bits + y*binary_bpr + (x/8)) |= (0x01 << (7 - x%8));
364 if ( (inside_lower_span == FALSE0) && (compare_2_pixels_with_variance(drawer->GetPixel(x,y+1),old_color,tolerance)) && sel->ContainsPoint(x,y+1) ) {
365 stack.Push(BPoint(x,y+1));
366 inside_lower_span = TRUE1;
367 }
368 else if ( (inside_lower_span == TRUE1) && (!compare_2_pixels_with_variance(drawer->GetPixel(x,y+1),old_color,tolerance) || !sel->ContainsPoint(x,y+1)) ) {
369 inside_lower_span = FALSE0;
370 }
371 x++;
372 }
373 }
374 }
375}
376
377void FillTool::CheckUpperSpans(BPoint span_start,BitmapDrawer *drawer,PointStack &stack,int32 min_x,int32 max_x,uint32 new_color,uint32 old_color,int32 tolerance,Selection *sel)
378{
379 // First get the vital data.
380 int32 x,start_x;
381 int32 y = (int32)span_start.y;
382 x = start_x = (int32)span_start.x;
383 bool inside_upper_span = FALSE0;
384
385 if ((sel == NULL__null) || (sel->IsEmpty() == TRUE1)) {
386 if ((tolerance == 0) && (binary_fill_map == NULL__null)) {
387 // Then go from start towards the left side of the bitmap.
388 while ( (x >= min_x) && (drawer->GetPixel(x,y) == old_color) ) {
389 drawer->SetPixel(x,y,new_color);
390 if ( (inside_upper_span == FALSE0) && (drawer->GetPixel(x,y-1) == old_color) ) {
391 stack.Push(BPoint(x,y-1));
392 inside_upper_span = TRUE1;
393 }
394 else if ( (inside_upper_span == TRUE1) && (drawer->GetPixel(x,y-1) != old_color) ) {
395 inside_upper_span = FALSE0;
396 }
397 x--;
398 }
399
400 // Then go from start_x+1 towards the right side of the bitmap.
401 // We might already be inside a lower span
402 inside_upper_span = ( drawer->GetPixel(start_x,y-1) == old_color );
403 x = start_x + 1;
404 while ( (x <= max_x) && (drawer->GetPixel(x,y) == old_color) ) {
405 drawer->SetPixel(x,y,new_color);
406 if ( (inside_upper_span == FALSE0) && (drawer->GetPixel(x,y-1) == old_color) ) {
407 stack.Push(BPoint(x,y-1));
408 inside_upper_span = TRUE1;
409 }
410 else if ( (inside_upper_span == TRUE1) && (drawer->GetPixel(x,y-1) != old_color) ) {
411 inside_upper_span = FALSE0;
412 }
413 x++;
414 }
415 }
416 else {
417 // This is the case that takes the variance into account. We must use a
418 // binary bitmap to see what parts have already been filled.
419 uint32 binary_bpr = binary_fill_map->BytesPerRow();
420 uchar *binary_bits = (uchar*)binary_fill_map->Bits();
421
422 // Then go from start towards the left side of the bitmap.
423 while ( (x >= min_x) && (compare_2_pixels_with_variance(drawer->GetPixel(x,y),old_color,tolerance)) && ((*(binary_bits + y*binary_bpr + (x/8))&(0x01 << (7-x%8))) == 0x00) ) {
424 drawer->SetPixel(x,y,new_color);
425 // *(binary_bits + y*binary_bpr + (x/8)) = *(binary_bits + y*binary_bpr + (x/8)) | (0x01 << (7 - x%8));
426 *(binary_bits + y*binary_bpr + (x/8)) |= (0x01 << (7 - x%8));
427 if ( (inside_upper_span == FALSE0) && (compare_2_pixels_with_variance(drawer->GetPixel(x,y-1),old_color,tolerance)) ) {
428 stack.Push(BPoint(x,y-1));
429 inside_upper_span = TRUE1;
430 }
431 else if ( (inside_upper_span == TRUE1) && (!compare_2_pixels_with_variance(drawer->GetPixel(x,y-1), old_color,tolerance)) ) {
432 inside_upper_span = FALSE0;
433 }
434 x--;
435 }
436
437 // Then go from start_x+1 towards the right side of the bitmap.
438 // We might already be inside a lower span
439 inside_upper_span = ( compare_2_pixels_with_variance(drawer->GetPixel(start_x,y-1) , old_color,tolerance) );
440 x = start_x + 1;
441 while ( (x <= max_x) && (compare_2_pixels_with_variance(drawer->GetPixel(x,y), old_color,tolerance)) && ((*(binary_bits + y*binary_bpr + (x/8))&(0x01 << (7-x%8))) == 0x00) ) {
442 drawer->SetPixel(x,y,new_color);
443 // *(binary_bits + y*binary_bpr + (x/8)) = *(binary_bits + y*binary_bpr + (x/8)) | (0x01 << (7 - x%8));
444 *(binary_bits + y*binary_bpr + (x/8)) |= (0x01 << (7 - x%8));
445 if ( (inside_upper_span == FALSE0) && (compare_2_pixels_with_variance(drawer->GetPixel(x,y-1),old_color,tolerance)) ) {
446 stack.Push(BPoint(x,y-1));
447 inside_upper_span = TRUE1;
448 }
449 else if ( (inside_upper_span == TRUE1) && (!compare_2_pixels_with_variance(drawer->GetPixel(x,y-1),old_color,tolerance)) ) {
450 inside_upper_span = FALSE0;
451 }
452 x++;
453 }
454 }
455 }
456 else {
457 if ((tolerance == 0) && (binary_fill_map == NULL__null)) {
458 // Then go from start towards the left side of the bitmap.
459 while (sel->ContainsPoint(x,y) && (x >= min_x) && (drawer->GetPixel(x,y) == old_color) ) {
460 drawer->SetPixel(x,y,new_color);
461 if ( (inside_upper_span == FALSE0) && (drawer->GetPixel(x,y-1) == old_color) && sel->ContainsPoint(x,y-1) ) {
462 stack.Push(BPoint(x,y-1));
463 inside_upper_span = TRUE1;
464 }
465 else if ( (inside_upper_span == TRUE1) && ((drawer->GetPixel(x,y-1) != old_color) || !sel->ContainsPoint(x,y-1)) ) {
466 inside_upper_span = FALSE0;
467 }
468 x--;
469 }
470
471 // Then go from start_x+1 towards the right side of the bitmap.
472 // We might already be inside a lower span
473 inside_upper_span = ( drawer->GetPixel(start_x,y-1) == old_color ) && sel->ContainsPoint(start_x,y-1);
474 x = start_x + 1;
475 while (sel->ContainsPoint(x,y) && (x <= max_x) && (drawer->GetPixel(x,y) == old_color) ) {
476 drawer->SetPixel(x,y,new_color);
477 if ( (inside_upper_span == FALSE0) && (drawer->GetPixel(x,y-1) == old_color) && sel->ContainsPoint(x,y-1)) {
478 stack.Push(BPoint(x,y-1));
479 inside_upper_span = TRUE1;
480 }
481 else if ( (inside_upper_span == TRUE1) && ((drawer->GetPixel(x,y-1) != old_color) || !sel->ContainsPoint(x,y-1)) ) {
482 inside_upper_span = FALSE0;
483 }
484 x++;
485 }
486 }
487 else {
488 // This is the case that takes the variance into account. We must use a
489 // binary bitmap to see what parts have already been filled.
490 uint32 binary_bpr = binary_fill_map->BytesPerRow();
491 uchar *binary_bits = (uchar*)binary_fill_map->Bits();
492
493 // Then go from start towards the left side of the bitmap.
494 while (sel->ContainsPoint(x,y) && (x >= min_x) && (compare_2_pixels_with_variance(drawer->GetPixel(x,y),old_color,tolerance)) && ((*(binary_bits + y*binary_bpr + (x/8))&(0x01 << (7-x%8))) == 0x00) ) {
495 drawer->SetPixel(x,y,new_color);
496 *(binary_bits + y*binary_bpr + (x/8)) |= (0x01 << (7 - x%8));
497 if ( (inside_upper_span == FALSE0) && (compare_2_pixels_with_variance(drawer->GetPixel(x,y-1),old_color,tolerance)) && sel->ContainsPoint(x,y-1) ) {
498 stack.Push(BPoint(x,y-1));
499 inside_upper_span = TRUE1;
500 }
501 else if ( (inside_upper_span == TRUE1) && (!compare_2_pixels_with_variance(drawer->GetPixel(x,y-1), old_color,tolerance) || !sel->ContainsPoint(x,y-1)) ) {
502 inside_upper_span = FALSE0;
503 }
504 x--;
505 }
506
507 // Then go from start_x+1 towards the right side of the bitmap.
508 // We might already be inside a lower span
509 inside_upper_span = ( compare_2_pixels_with_variance(drawer->GetPixel(start_x,y-1) , old_color,tolerance) && sel->ContainsPoint(start_x,y-1));
510 x = start_x + 1;
511 while (sel->ContainsPoint(x,y) && (x <= max_x) && (compare_2_pixels_with_variance(drawer->GetPixel(x,y), old_color,tolerance)) && ((*(binary_bits + y*binary_bpr + (x/8))&(0x01 << (7-x%8))) == 0x00) ) {
512 drawer->SetPixel(x,y,new_color);
513 *(binary_bits + y*binary_bpr + (x/8)) |= (0x01 << (7 - x%8));
514 if ( (inside_upper_span == FALSE0) && (compare_2_pixels_with_variance(drawer->GetPixel(x,y-1),old_color,tolerance)) && sel->ContainsPoint(x,y-1) ) {
515 stack.Push(BPoint(x,y-1));
516 inside_upper_span = TRUE1;
517 }
518 else if ( (inside_upper_span == TRUE1) && (!compare_2_pixels_with_variance(drawer->GetPixel(x,y-1),old_color,tolerance) || !sel->ContainsPoint(x,y-1)) ) {
519 inside_upper_span = FALSE0;
520 }
521 x++;
522 }
523 }
524 }
525}
526
527void
528FillTool::CheckBothSpans(BPoint span_start,BitmapDrawer *drawer,PointStack &stack,int32 min_x,int32 max_x,uint32 new_color,uint32 old_color,int32 tolerance,Selection *sel)
529{
530 // First get the vital data.
531 int32 x,start_x;
532 int32 y = (int32)span_start.y;
533 x = start_x = (int32)span_start.x;
534 bool inside_lower_span = FALSE0;
535 bool inside_upper_span = FALSE0;
536
537 if ((sel == NULL__null) || (sel->IsEmpty() == TRUE1)) {
538 if ((tolerance == 0) && (binary_fill_map == NULL__null)) {
539 // Then go from start towards the left side of the bitmap.
540 while ( (x >= min_x) && (drawer->GetPixel(x,y) == old_color) ) {
541 drawer->SetPixel(x,y,new_color);
542
543 if ( (inside_lower_span == FALSE0) && (drawer->GetPixel(x,y+1) == old_color) ) {
544 stack.Push(BPoint(x,y+1));
545 inside_lower_span = TRUE1;
546 }
547 else if ( (inside_lower_span == TRUE1) && (drawer->GetPixel(x,y+1) != old_color) ) {
548 inside_lower_span = FALSE0;
549 }
550
551 if ( (inside_upper_span == FALSE0) && (drawer->GetPixel(x,y-1) == old_color) ) {
552 stack.Push(BPoint(x,y-1));
553 inside_upper_span = TRUE1;
554 }
555 else if ( (inside_upper_span == TRUE1) && (drawer->GetPixel(x,y-1) != old_color) ) {
556 inside_upper_span = FALSE0;
557 }
558
559 x--;
560 }
561
562 // Then go from start_x+1 towards the right side of the bitmap.
563 // We might already be inside a lower span
564 inside_lower_span = ( drawer->GetPixel(start_x,y+1) == old_color );
565 inside_upper_span = ( drawer->GetPixel(start_x,y-1) == old_color );
566 x = start_x + 1;
567 while ( (x <= max_x) && (drawer->GetPixel(x,y) == old_color) ) {
568 drawer->SetPixel(x,y,new_color);
569
570 if ( (inside_lower_span == FALSE0) && (drawer->GetPixel(x,y+1) == old_color) ) {
571 stack.Push(BPoint(x,y+1));
572 inside_lower_span = TRUE1;
573 }
574 else if ( (inside_lower_span == TRUE1) && (drawer->GetPixel(x,y+1) != old_color) ) {
575 inside_lower_span = FALSE0;
576 }
577
578 if ( (inside_upper_span == FALSE0) && (drawer->GetPixel(x,y-1) == old_color) ) {
579 stack.Push(BPoint(x,y-1));
580 inside_upper_span = TRUE1;
581 }
582 else if ( (inside_upper_span == TRUE1) && (drawer->GetPixel(x,y-1) != old_color) ) {
583 inside_upper_span = FALSE0;
584 }
585
586 x++;
587 }
588 }
589 else {
590 // This is the case that takes the variance into account. We must use a
591 // binary bitmap to see what parts have already been filled.
592 uint32 binary_bpr = binary_fill_map->BytesPerRow();
593 uchar *binary_bits = (uchar*)binary_fill_map->Bits();
594
595 // Then go from start towards the left side of the bitmap.
596 while ( (x >= min_x) && (compare_2_pixels_with_variance(drawer->GetPixel(x,y), old_color,tolerance)) && ((*(binary_bits + y*binary_bpr + (x/8))&(0x01 << (7-x%8))) == 0x00) ) {
597 drawer->SetPixel(x,y,new_color);
598 // *(binary_bits + y*binary_bpr + (x/8)) = *(binary_bits + y*binary_bpr + (x/8)) | (0x01 << (7 - x%8));
599 *(binary_bits + y*binary_bpr + (x/8)) |= (0x01 << (7 - x%8));
600
601 if ( (inside_lower_span == FALSE0) && (compare_2_pixels_with_variance(drawer->GetPixel(x,y+1),old_color,tolerance)) ) {
602 stack.Push(BPoint(x,y+1));
603 inside_lower_span = TRUE1;
604 }
605 else if ( (inside_lower_span == TRUE1) && (!compare_2_pixels_with_variance(drawer->GetPixel(x,y+1),old_color,tolerance)) ) {
606 inside_lower_span = FALSE0;
607 }
608
609 if ( (inside_upper_span == FALSE0) && (compare_2_pixels_with_variance(drawer->GetPixel(x,y-1),old_color,tolerance)) ) {
610 stack.Push(BPoint(x,y-1));
611 inside_upper_span = TRUE1;
612 }
613 else if ( (inside_upper_span == TRUE1) && (!compare_2_pixels_with_variance(drawer->GetPixel(x,y-1), old_color,tolerance)) ) {
614 inside_upper_span = FALSE0;
615 }
616
617 x--;
618 }
619
620 // Then go from start_x+1 towards the right side of the bitmap.
621 // We might already be inside a lower span
622 inside_lower_span = ( compare_2_pixels_with_variance(drawer->GetPixel(start_x,y+1),old_color,tolerance) );
623 inside_upper_span = ( compare_2_pixels_with_variance(drawer->GetPixel(start_x,y-1), old_color,tolerance) );
624 x = start_x + 1;
625 while ( (x <= max_x) && (compare_2_pixels_with_variance(drawer->GetPixel(x,y),old_color,tolerance)) && ((*(binary_bits + y*binary_bpr + (x/8))&(0x01 << (7-x%8))) == 0x00) ) {
626 drawer->SetPixel(x,y,new_color);
627 // *(binary_bits + y*binary_bpr + (x/8)) = *(binary_bits + y*binary_bpr + (x/8)) | (0x01 << (7 - x%8));
628 *(binary_bits + y*binary_bpr + (x/8)) |= (0x01 << (7 - x%8));
629
630 if ( (inside_lower_span == FALSE0) && (compare_2_pixels_with_variance(drawer->GetPixel(x,y+1),old_color,tolerance)) ) {
631 stack.Push(BPoint(x,y+1));
632 inside_lower_span = TRUE1;
633 }
634 else if ( (inside_lower_span == TRUE1) && (!compare_2_pixels_with_variance(drawer->GetPixel(x,y+1),old_color,tolerance)) ) {
635 inside_lower_span = FALSE0;
636 }
637
638 if ( (inside_upper_span == FALSE0) && (compare_2_pixels_with_variance(drawer->GetPixel(x,y-1), old_color,tolerance)) ) {
639 stack.Push(BPoint(x,y-1));
640 inside_upper_span = TRUE1;
641 }
642 else if ( (inside_upper_span == TRUE1) && (!compare_2_pixels_with_variance(drawer->GetPixel(x,y-1),old_color,tolerance)) ) {
643 inside_upper_span = FALSE0;
644 }
645
646 x++;
647 }
648 }
649 }
650 else {
651 if ((tolerance == 0) && (binary_fill_map == NULL__null)) {
652 // Then go from start towards the left side of the bitmap.
653 while (sel->ContainsPoint(x,y) && (x >= min_x) && (drawer->GetPixel(x,y) == old_color) ) {
654 drawer->SetPixel(x,y,new_color);
655
656 if ( (inside_lower_span == FALSE0) && (drawer->GetPixel(x,y+1) == old_color) && sel->ContainsPoint(x,y+1)) {
657 stack.Push(BPoint(x,y+1));
658 inside_lower_span = TRUE1;
659 }
660 else if ( (inside_lower_span == TRUE1) && ((drawer->GetPixel(x,y+1) != old_color) || !sel->ContainsPoint(x,y+1)) ) {
661 inside_lower_span = FALSE0;
662 }
663
664 if ( (inside_upper_span == FALSE0) && (drawer->GetPixel(x,y-1) == old_color) && sel->ContainsPoint(x,y-1)) {
665 stack.Push(BPoint(x,y-1));
666 inside_upper_span = TRUE1;
667 }
668 else if ( (inside_upper_span == TRUE1) && ((drawer->GetPixel(x,y-1) != old_color) || !sel->ContainsPoint(x,y-1))) {
669 inside_upper_span = FALSE0;
670 }
671
672 x--;
673 }
674
675 // Then go from start_x+1 towards the right side of the bitmap.
676 // We might already be inside a lower span
677 inside_lower_span = ( drawer->GetPixel(start_x,y+1) == old_color ) && sel->ContainsPoint(x,y+1);
678 inside_upper_span = ( drawer->GetPixel(start_x,y-1) == old_color ) && sel->ContainsPoint(x,y-1);
679 x = start_x + 1;
680 while (sel->ContainsPoint(x,y) && (x <= max_x) && (drawer->GetPixel(x,y) == old_color) ) {
681 drawer->SetPixel(x,y,new_color);
682
683 if ( (inside_lower_span == FALSE0) && (drawer->GetPixel(x,y+1) == old_color) && sel->ContainsPoint(x,y+1)) {
684 stack.Push(BPoint(x,y+1));
685 inside_lower_span = TRUE1;
686 }
687 else if ( (inside_lower_span == TRUE1) && ((drawer->GetPixel(x,y+1) != old_color) || !sel->ContainsPoint(x,y+1)) ) {
688 inside_lower_span = FALSE0;
689 }
690
691 if ( (inside_upper_span == FALSE0) && (drawer->GetPixel(x,y-1) == old_color) && sel->ContainsPoint(x,y-1)) {
692 stack.Push(BPoint(x,y-1));
693 inside_upper_span = TRUE1;
694 }
695 else if ( (inside_upper_span == TRUE1) && ((drawer->GetPixel(x,y-1) != old_color) || !sel->ContainsPoint(x,y-1)) ) {
696 inside_upper_span = FALSE0;
697 }
698
699 x++;
700 }
701 }
702 else {
703 // This is the case that takes the variance into account. We must use a
704 // binary bitmap to see what parts have already been filled.
705 uint32 binary_bpr = binary_fill_map->BytesPerRow();
706 uchar *binary_bits = (uchar*)binary_fill_map->Bits();
707
708 // Then go from start towards the left side of the bitmap.
709 while (sel->ContainsPoint(x,y) && (x >= min_x) && (compare_2_pixels_with_variance(drawer->GetPixel(x,y), old_color,tolerance)) && ((*(binary_bits + y*binary_bpr + (x/8))&(0x01 << (7-x%8))) == 0x00) ) {
710 drawer->SetPixel(x,y,new_color);
711 *(binary_bits + y*binary_bpr + (x/8)) |= (0x01 << (7 - x%8));
712
713 if ( (inside_lower_span == FALSE0) && (compare_2_pixels_with_variance(drawer->GetPixel(x,y+1),old_color,tolerance)) && sel->ContainsPoint(x,y+1) ) {
714 stack.Push(BPoint(x,y+1));
715 inside_lower_span = TRUE1;
716 }
717 else if ( (inside_lower_span == TRUE1) && (!compare_2_pixels_with_variance(drawer->GetPixel(x,y+1),old_color,tolerance) || !sel->ContainsPoint(x,y+1)) ) {
718 inside_lower_span = FALSE0;
719 }
720
721 if ( (inside_upper_span == FALSE0) && (compare_2_pixels_with_variance(drawer->GetPixel(x,y-1),old_color,tolerance)) && sel->ContainsPoint(x,y-1) ) {
722 stack.Push(BPoint(x,y-1));
723 inside_upper_span = TRUE1;
724 }
725 else if ( (inside_upper_span == TRUE1) && (!compare_2_pixels_with_variance(drawer->GetPixel(x,y-1), old_color,tolerance) || !sel->ContainsPoint(x,y-1)) ) {
726 inside_upper_span = FALSE0;
727 }
728
729 x--;
730 }
731
732 // Then go from start_x+1 towards the right side of the bitmap.
733 // We might already be inside a lower span
734 inside_lower_span = ( compare_2_pixels_with_variance(drawer->GetPixel(start_x,y+1),old_color,tolerance) && sel->ContainsPoint(start_x,y+1));
735 inside_upper_span = ( compare_2_pixels_with_variance(drawer->GetPixel(start_x,y-1),old_color,tolerance) && sel->ContainsPoint(start_x,y-1));
736 x = start_x + 1;
737 while (sel->ContainsPoint(x,y) && (x <= max_x) && (compare_2_pixels_with_variance(drawer->GetPixel(x,y),old_color,tolerance)) && ((*(binary_bits + y*binary_bpr + (x/8))&(0x01 << (7-x%8))) == 0x00) ) {
738 drawer->SetPixel(x,y,new_color);
739 *(binary_bits + y*binary_bpr + (x/8)) |= (0x01 << (7 - x%8));
740
741 if ( (inside_lower_span == FALSE0) && (compare_2_pixels_with_variance(drawer->GetPixel(x,y+1),old_color,tolerance)) && sel->ContainsPoint(x,y+1) ) {
742 stack.Push(BPoint(x,y+1));
743 inside_lower_span = TRUE1;
744 }
745 else if ( (inside_lower_span == TRUE1) && (!compare_2_pixels_with_variance(drawer->GetPixel(x,y+1),old_color,tolerance) || !sel->ContainsPoint(x,y+1)) ) {
746 inside_lower_span = FALSE0;
747 }
748
749 if ( (inside_upper_span == FALSE0) && (compare_2_pixels_with_variance(drawer->GetPixel(x,y-1), old_color,tolerance)) && sel->ContainsPoint(x,y-1) ) {
750 stack.Push(BPoint(x,y-1));
751 inside_upper_span = TRUE1;
752 }
753 else if ( (inside_upper_span == TRUE1) && (!compare_2_pixels_with_variance(drawer->GetPixel(x,y-1),old_color,tolerance) || !sel->ContainsPoint(x,y-1)) ) {
754 inside_upper_span = FALSE0;
755 }
756
757 x++;
758 }
759 }
760 }
761}
762
763
764void
765FillTool::FillSpan(BPoint span_start,BitmapDrawer *drawer,int32 min_x, int32 max_x, uint32 new_color, uint32 old_color,int32 tolerance,Selection *sel)
766{
767 // First get the vital data.
768 int32 x,start_x;
769 int32 y = (int32)span_start.y;
770 x = start_x = (int32)span_start.x;
771
772 if ((sel == NULL__null) || (sel->IsEmpty() == TRUE1)) {
773 if ((tolerance == 0) && (binary_fill_map == NULL__null)) {
774 // Then go from start towards the left side of the bitmap.
775 while ( (x >= min_x) && (drawer->GetPixel(x,y) == old_color) ) {
776 drawer->SetPixel(x,y,new_color);
777 x--;
778 }
779
780 // Then go from start_x+1 towards the right side of the bitmap.
781 x = start_x + 1;
782 while ( (x <= max_x) && (drawer->GetPixel(x,y) == old_color) ) {
783 drawer->SetPixel(x,y,new_color);
784 x++;
785 }
786 }
787 else {
788 // This is the case that takes the variance into account. We must use a
789 // binary bitmap to see what parts have already been filled.
790 uint32 binary_bpr = binary_fill_map->BytesPerRow();
791 uchar *binary_bits = (uchar*)binary_fill_map->Bits();
792
793 // Then go from start towards the left side of the bitmap.
794 while ( (x >= min_x) && (compare_2_pixels_with_variance(drawer->GetPixel(x,y), old_color,tolerance)) ) {
795 drawer->SetPixel(x,y,new_color);
796 *(binary_bits + y*binary_bpr + (x/8)) = *(binary_bits + y*binary_bpr + (x/8)) | (0x01 << (7 - x%8));
797 x--;
798 }
799
800 // Then go from start_x+1 towards the right side of the bitmap.
801 x = start_x + 1;
802 while ( (x <= max_x) && (compare_2_pixels_with_variance(drawer->GetPixel(x,y),old_color,tolerance)) ) {
803 drawer->SetPixel(x,y,new_color);
804 *(binary_bits + y*binary_bpr + (x/8)) = *(binary_bits + y*binary_bpr + (x/8)) | (0x01 << (7 - x%8));
805 x++;
806 }
807
808 }
809 }
810 else {
811 if ((tolerance == 0) && (binary_fill_map == NULL__null)) {
812 // Then go from start towards the left side of the bitmap.
813 while (sel->ContainsPoint(x,y) && (x >= min_x) && (drawer->GetPixel(x,y) == old_color) ) {
814 drawer->SetPixel(x,y,new_color);
815 x--;
816 }
817
818 // Then go from start_x+1 towards the right side of the bitmap.
819 x = start_x + 1;
820 while (sel->ContainsPoint(x,y) && (x <= max_x) && (drawer->GetPixel(x,y) == old_color) ) {
821 drawer->SetPixel(x,y,new_color);
822 x++;
823 }
824 }
825 else {
826 // This is the case that takes the variance into account. We must use a
827 // binary bitmap to see what parts have already been filled.
828 uint32 binary_bpr = binary_fill_map->BytesPerRow();
829 uchar *binary_bits = (uchar*)binary_fill_map->Bits();
830
831 // Then go from start towards the left side of the bitmap.
832 while (sel->ContainsPoint(x,y) && (x >= min_x) && (compare_2_pixels_with_variance(drawer->GetPixel(x,y), old_color,tolerance)) ) {
833 drawer->SetPixel(x,y,new_color);
834 *(binary_bits + y*binary_bpr + (x/8)) = *(binary_bits + y*binary_bpr + (x/8)) | (0x01 << (7 - x%8));
835 x--;
836 }
837
838 // Then go from start_x+1 towards the right side of the bitmap.
839 x = start_x + 1;
840 while (sel->ContainsPoint(x,y) && (x <= max_x) && (compare_2_pixels_with_variance(drawer->GetPixel(x,y),old_color,tolerance)) ) {
841 drawer->SetPixel(x,y,new_color);
842 *(binary_bits + y*binary_bpr + (x/8)) = *(binary_bits + y*binary_bpr + (x/8)) | (0x01 << (7 - x%8));
843 x++;
844 }
845
846 }
847 }
848}
849
850
851BPoint
852FillTool::GradientFill(ImageView *view,uint32 buttons,BPoint start,BPoint orig_view_point,Selection *sel)
853{
854 // First calculate points that are to be included in the fill to
855 // a separate binary mask. Then go through the filled areas bounds
856 // rectangle and fill only those pixels that the mask tells to.
857 // The color of pixel is to be calculated from the original mousedown point
858 // and the last mousedown point and from color values for mouse-button
859 // and gradien color. If preview is enabled we should also update in real time
860 // whenever possible.
861
862 // Get the necessary parameters
863 // Wait for the last_updated_region to become empty
864 while (LastUpdatedRect().IsValid())
865 snooze(50000);
866
867 BWindow *window = view->Window();
868 if (window == NULL__null)
869 return BPoint(-1,-1);
870
871 BBitmap *bitmap = view->ReturnImage()->ReturnActiveBitmap();
872 BitmapDrawer *drawer = new BitmapDrawer(bitmap);
873 BRect bitmap_bounds = bitmap->Bounds();
874 bitmap_bounds.OffsetTo(BPoint(0,0));
875
876 window->Lock();
877 drawing_mode old_mode = view->DrawingMode();
878 view->SetDrawingMode(B_OP_INVERT);
879 window->Unlock();
880 BPoint new_point = start;
881
882 if (bitmap_bounds.Contains(start) == TRUE1) {
883
884 // These are the edge coordinates of bitmap. It is still safe to
885 // address a pixel at max_x,max_y or min_x,min_y.
886 int32 min_x,min_y,max_x,max_y;
887 min_x = (int32)bitmap_bounds.left;
888 min_y = (int32)bitmap_bounds.top;
889 max_x = (int32)bitmap_bounds.right;
890 max_y = (int32)bitmap_bounds.bottom;
891
892 // At this point we should take some action if min_x == max_x or min_y == max_y
893
894 // Get the color for the fill.
895// rgb_color c = ((PaintApplication*)be_app)->Color(buttons);
896// uint32 color = RGBColorToBGRA(c);
897
898// // Get the gradient color.
899// uint32 gradient_color = settings.gradient_color;
900 // Get the old color.
901 uint32 old_color = drawer->GetPixel(start);
902
903 uint32 gradient_color = gradient_color1;
904 uint32 color = gradient_color2;
905
906 // Here calculate the binary bitmap for the purpose of doing the gradient.
907 BBitmap *binary_map;
908 if (fToolSettings.mode == B_CONTROL_OFF) // Not flood-mode
909 binary_map = MakeBinaryMap(drawer,min_x,max_x,min_y,max_y,old_color,sel);
910 else // Flood-mode
911 binary_map = MakeFloodBinaryMap(drawer,min_x,max_x,min_y,max_y,old_color,start,sel);
912
913
914 // Here calculate the bounding rectangle of the filled area and
915 // change the min and max coordinates to those edges of the rect.
916 BRect filled_area_bounds = calcBinaryMapBounds(binary_map);
917// min_x = filled_area_bounds.left;
918// max_x = filled_area_bounds.right;
919// min_y = filled_area_bounds.top;
920// max_y = filled_area_bounds.bottom;
921
922 BRect ellipse_rect = BRect(orig_view_point-BPoint(3,3),orig_view_point+BPoint(3,3));
923 BPoint new_view_point = orig_view_point;
924 BPoint prev_view_point = new_view_point;
925 window->Lock();
926 view->StrokeEllipse(ellipse_rect);
927 window->Unlock();
928 if (fToolSettings.preview_enabled == B_CONTROL_OFF) {
929 // Do not do the preview. Just read the coordinates.
930 while (buttons) {
931 if (new_view_point != prev_view_point) {
932 window->Lock();
933 view->StrokeEllipse(ellipse_rect);
934 window->Unlock();
935 prev_view_point = new_view_point;
936 }
937 window->Lock();
938 view->getCoords(&new_point,&buttons,&new_view_point);
939 window->Unlock();
940 snooze(20 * 1000);
941 }
942 }
943 else {
944 // Display also preview of the gradient
945 while (buttons) {
946 if (new_view_point != prev_view_point) {
947 int32 dx = (int32)(start.x - new_point.x);
948 int32 dy = (int32)(start.y - new_point.y);
949 // There should actually be a separate function (and maybe even a thread) that calculates
950 // the preview in real time for some bitmap that is quite small (about 200x200 pixels maximum).
951 // Then the gradient would be copied to bitmap using some specialized function.
952 FillGradientPreview(drawer,binary_map,dx,dy,min_x,max_x,min_y,max_y,color,gradient_color);
953 view->ReturnImage()->RenderPreview(bitmap->Bounds(),2);
954 window->Lock();
955 view->Draw(view->convertBitmapRectToView(filled_area_bounds));
956 view->StrokeEllipse(ellipse_rect);
957 window->Unlock();
958 prev_view_point = new_view_point;
959 }
960 window->Lock();
961 view->getCoords(&new_point,&buttons,&new_view_point);
962 window->Unlock();
963 snooze(20 * 1000);
964 }
965 }
966 // Here calculate the final gradient.
967 int32 dx = (int32)(start.x - new_point.x);
968 int32 dy = (int32)(start.y - new_point.y);
969
970 FillGradient(drawer,binary_map,dx,dy,min_x,max_x,min_y,max_y,color,gradient_color);
971
972 // Update the image-view.
973 view->ReturnImage()->Render();
974 window->Lock();
975 view->SetDrawingMode(old_mode);
976 view->Draw(view->convertBitmapRectToView(filled_area_bounds) | ellipse_rect);
977 window->Unlock();
978 delete binary_map;
979 SetLastUpdatedRect(filled_area_bounds);
980 }
981 delete drawer;
982 return new_point;
983}
984
985
986
987BBitmap*
988FillTool::MakeBinaryMap(BitmapDrawer *drawer,int32 min_x,int32 max_x,int32 min_y,int32 max_y,uint32 old_color,Selection *sel)
989{
990 // This function makes a binary bitmap that has ones where the
991 // color of original bitmap is same as old_color, and zeroes elsewhere.
992 BBitmap *binary_map = new BBitmap(BRect(min_x,min_y,max_x,max_y), B_GRAY1);
993 uchar *binary_bits = (uchar*)binary_map->Bits();
994 int32 binary_bpr = binary_map->BytesPerRow();
995
996 if ((sel == NULL__null) || (sel->IsEmpty() == TRUE1)) {
997 if (fToolSettings.tolerance == 0) {
998 // Always collect eight pixels from the bitmap and then move that data to the binary bitmap.
999 uchar next_value = 0x00;
1000 for (int32 y=min_y;y<=max_y;y++) {
1001 int32 bytes_advanced = 0;
1002 for (int32 x=min_x;x<=max_x;x++) {
1003 if ( ((x % 8) == 0) && (x != 0) ) {
1004 *binary_bits++ = next_value;
1005 bytes_advanced++;
1006 next_value = 0x00;
1007 }
1008 next_value |= ( (old_color == drawer->GetPixel(x,y)) ? ( 0x01 << (7 - (x%8) )) : 0x00 );
1009 }
1010 if ((max_x % 8) != 0) {
1011 *binary_bits++ = next_value;
1012 bytes_advanced++;
1013 next_value = 0x00;
1014 }
1015 binary_bits += binary_bpr - bytes_advanced;
1016 }
1017 }
1018 else {
1019 // Always collect eight pixels from the bitmap and then move that data to the binary bitmap.
1020 uchar next_value = 0x00;
1021 uint32 tolerance = (uint32)((float)fToolSettings.tolerance/100.0 * 255);
1022 for (int32 y=min_y;y<=max_y;y++) {
1023 int32 bytes_advanced = 0;
1024 for (int32 x=min_x;x<=max_x;x++) {
1025 if ( ((x % 8) == 0) && (x != 0) ) {
1026 *binary_bits++ = next_value;
1027 bytes_advanced++;
1028 next_value = 0x00;
1029 }
1030 next_value |= ( (compare_2_pixels_with_variance(old_color,drawer->GetPixel(x,y),tolerance)) ? ( 0x01 << (7 - (x%8) )) : 0x00 );
1031 }
1032 if ((max_x % 8) != 0) {
1033 *binary_bits++ = next_value;
1034 bytes_advanced++;
1035 next_value = 0x00;
1036 }
1037 binary_bits += binary_bpr - bytes_advanced;
1038 }
1039 }
1040 }
1041 else {
1042 if (fToolSettings.tolerance == 0) {
1043 // Always collect eight pixels from the bitmap and then move that data to the binary bitmap.
1044 uchar next_value = 0x00;
1045 for (int32 y=min_y;y<=max_y;y++) {
1046 int32 bytes_advanced = 0;
1047 for (int32 x=min_x;x<=max_x;x++) {
1048 if ( ((x % 8) == 0) && (x != 0) ) {
1049 *binary_bits++ = next_value;
1050 bytes_advanced++;
1051 next_value = 0x00;
1052 }
1053 next_value |= ( ((old_color == drawer->GetPixel(x,y)) && sel->ContainsPoint(x,y)) ? ( 0x01 << (7 - (x%8) )) : 0x00 );
1054 }
1055 if ((max_x % 8) != 0) {
1056 *binary_bits++ = next_value;
1057 bytes_advanced++;
1058 next_value = 0x00;
1059 }
1060 binary_bits += binary_bpr - bytes_advanced;
1061 }
1062 }
1063 else {
1064 // Always collect eight pixels from the bitmap and then move that data to the binary bitmap.
1065 uchar next_value = 0x00;
1066 uint32 tolerance = (uint32)((float)fToolSettings.tolerance/100.0 * 255);
1067 for (int32 y=min_y;y<=max_y;y++) {
1068 int32 bytes_advanced = 0;
1069 for (int32 x=min_x;x<=max_x;x++) {
1070 if ( ((x % 8) == 0) && (x != 0) ) {
1071 *binary_bits++ = next_value;
1072 bytes_advanced++;
1073 next_value = 0x00;
1074 }
1075 next_value |= ( (compare_2_pixels_with_variance(old_color,drawer->GetPixel(x,y),tolerance) && sel->ContainsPoint(x,y)) ? ( 0x01 << (7 - (x%8) )) : 0x00 );
1076 }
1077 if ((max_x % 8) != 0) {
1078 *binary_bits++ = next_value;
1079 bytes_advanced++;
1080 next_value = 0x00;
1081 }
1082 binary_bits += binary_bpr - bytes_advanced;
1083 }
1084 }
1085 }
1086 return binary_map;
1087}
1088
1089BBitmap*
1090FillTool::MakeFloodBinaryMap(BitmapDrawer *drawer, int32 min_x,
1091 int32 max_x, int32 min_y, int32 max_y, uint32 old_color, BPoint start,
1092 Selection *sel)
1093{
1094 // This function makes a binary bitmap of the image. It contains ones where
1095 // the flood fill should fill and zeroes elsewhere.
1096 BBitmap *binary_map;
1097 binary_map = binary_fill_map = new BBitmap(BRect(min_x,min_y,max_x,max_y),
1098 B_GRAY1);
1099 uchar *binary_bits = (uchar*)binary_map->Bits();
1100 int32 binary_bitslength = binary_map->BitsLength();
1101 // Clear the binary map.
1102 for (int32 i=0;i<binary_bitslength;i++)
1103 *binary_bits++ = 0x00;
1104
1105 binary_bits = (uchar*)binary_map->Bits();
1106
1107 // We can use the functions CheckLowerSpans, CheckUpperSpans and CheckBothSpans
1108 // to calculate the binary_fill_map and then return it.
1109
1110 // Here we proceed just like in the case of a normal fill, except that we do not
1111 // show the intermediate fill to the user.
1112
1113 // Here fill the area using drawer's SetPixel and GetPixel.
1114 // The algorithm uses 4-connected version of flood-fill.
1115 // The SetPixel and GetPixel functions are versions that
1116 // do not check bounds so we have to be careful not to exceed
1117 // bitmap's bounds.
1118 uint32 color = 0xFFFFFFFF; // This is the temporary color that will be used
1119 // to fill the bitmap.
1120 uint32 tolerance = (uint32)((float)fToolSettings.tolerance/100.0 * 255);
1121
1122 PointStack stack;
1123 stack.Push(start);
1124
1125 while (!stack.IsEmpty()) {
1126 BPoint span_start = stack.Pop();
1127 if ( (span_start.y == min_y) && (min_y != max_y) ) {
1128 // Only check the spans below this line
1129 CheckLowerSpans(span_start,drawer, stack,min_x,max_x,color,old_color,tolerance,sel);
1130 }
1131 else if ( (span_start.y == max_y) && (min_y != max_y) ) {
1132 // Only check the spans above this line.
1133 CheckUpperSpans(span_start,drawer, stack,min_x,max_x,color,old_color,tolerance,sel);
1134 }
1135 else if (min_y != max_y) {
1136 // Check the spans above and below this line.
1137 CheckBothSpans(span_start,drawer, stack,min_x,max_x,color,old_color,tolerance,sel);
1138 }
1139 else {
1140 // The image is only one pixel high. Fill the only span.
1141 FillSpan(span_start,drawer,min_x,max_x,color,old_color,tolerance,sel);
1142 }
1143 }
1144
1145 // Remember to NULL the attribute binary_fill_map
1146 binary_fill_map = NULL__null;
1147 return binary_map;
1148}
1149
1150
1151void
1152FillTool::FillGradient(BitmapDrawer *drawer, BBitmap *binary_map, int32 dx,
1153 int32 dy, int32 min_x, int32 max_x, int32 min_y, int32 max_y,
1154 uint32 new_color, uint32 gradient_color)
1155{
1156 uchar *binary_bits = (uchar*)binary_map->Bits();
1157 int32 binary_bpr = binary_map->BytesPerRow();
1158
1159 uint32 x_source,x_target;
1160 uint32 y_source,y_target;
1161
1162 if (dx < 0)
1163 x_target = gradient_color;
1164 else
1165 x_target = new_color;
1166
1167 if (dy<0) {
1168 y_target = gradient_color;
1169 y_source = new_color;
1170 } else {
1171 y_target = new_color;
1172 y_source = gradient_color;
1173 }
1174 uint32 y_gradient;
1175 uint32 x_gradient;
1176
1177 // These might also be negative
1178 int16 x_red_diff,x_green_diff,x_blue_diff,x_alpha_diff;
1179 int16 y_red_diff,y_green_diff,y_blue_diff,y_alpha_diff;
1180
1181 float x_accumulation;
1182 float y_accumulation = 0;
1183
1184 y_gradient = y_source;
1185 uchar next_value = 0;
1186
1187 y_red_diff = (int16)((y_target>>8) & 0xFF) - (int16)((y_source>>8) & 0xFF);
1188 y_green_diff = (int16)((y_target>>16) & 0xFF) - (int16)((y_source>>16) & 0xFF);
1189 y_blue_diff = (int16)((y_target>>24) & 0xFF) - (int16)((y_source>>24) & 0xFF);
1190 y_alpha_diff = (int16)((y_target) & 0xFF) - (int16)((y_source) & 0xFF);
1191
1192
1193 for (int32 y = min_y; y <=max_y; ++y) {
1194 int32 bytes_advanced = 0;
1195 // Here we should move y-gradient 1 step closer to y-target
1196 // and put x-source to y-gradient. We should also recalculate
1197 // the x-gradient step.
1198 if (dy<0) {
1199 y_accumulation = (float)(abs(dy))/50.0*(float)(max_y-y)/(float)(max_y - min_y);
1200 if (y_accumulation < 1.0) {
1201 y_gradient = y_source
1202 + (((int32)(y_blue_diff * (1.0-y_accumulation))) << 24)
1203 + (((int32)(y_green_diff * (1.0-y_accumulation))) << 16)
1204 + (((int32)(y_red_diff * (1.0-y_accumulation))) << 8)
1205 + (((int32)(y_alpha_diff * (1.0-y_accumulation))));
1206 } else {
1207 y_gradient = y_source;
1208 }
1209 } else {
1210 y_accumulation = (float)dy/50.0*(float)y/(float)(max_y - min_y);
1211 if (y_accumulation < 1.0) {
1212 y_gradient = y_source
1213 + (((int32)(y_blue_diff * y_accumulation)) << 24)
1214 + (((int32)(y_green_diff * y_accumulation)) << 16)
1215 + (((int32)(y_red_diff * y_accumulation)) << 8)
1216 + (((int32)(y_alpha_diff * y_accumulation)));
1217 } else {
1218 y_gradient = y_target;
1219 }
1220 }
1221
1222 if (dx < 0) {
1223 x_source = new_color;
1224 x_target = y_gradient;
1225 } else {
1226 x_source = y_gradient;
1227 x_target = new_color;
1228 }
1229
1230 x_red_diff = (int16)((x_target>>8) & 0xFF) - (int16)((x_source>>8) & 0xFF);
1231 x_green_diff = (int16)((x_target>>16) & 0xFF) - (int16)((x_source>>16) & 0xFF);
1232 x_blue_diff = (int16)((x_target>>24) & 0xFF) - (int16)((x_source>>24) & 0xFF);
1233 x_alpha_diff = (int16)((x_target) & 0xFF) - (int16)((x_source) & 0xFF);
1234
1235 x_accumulation = 0;
Value stored to 'x_accumulation' is never read
1236 for (int32 x=min_x;x<=max_x;x++) {
1237 // This might crash if max_x == min_x
1238 if (dx < 0)
1239 x_accumulation = (float)abs(dx)/50.0*(float)(max_x-x)/(float)(max_x - min_x);
1240 else
1241 x_accumulation = (float)dx/50.0*(float)x/(float)(max_x - min_x);
1242
1243 if ( (x % 8) == 0 ) {
1244 next_value = *binary_bits++;
1245 bytes_advanced++;
1246 }
1247 if ( next_value & (0x01 << (7-(x%8))) ) {
1248 // Here we should put a new value into position x,y
1249 if (dx<0) {
1250 if (x_accumulation < 1.0) {
1251 x_gradient = x_source
1252 + (((int32)(x_blue_diff * (1.0-x_accumulation))) << 24)
1253 + (((int32)(x_green_diff * (1.0-x_accumulation))) << 16)
1254 + (((int32)(x_red_diff * (1.0-x_accumulation))) << 8)
1255 + (((int32)(x_alpha_diff * (1.0-x_accumulation))));
1256 drawer->SetPixel(x,y,x_gradient);
1257 } else {
1258 drawer->SetPixel(x, y, x_source);
1259 }
1260 } else {
1261 if (x_accumulation < 1.0) {
1262 x_gradient = x_source
1263 + (((int32)(x_blue_diff * x_accumulation)) << 24)
1264 + (((int32)(x_green_diff * x_accumulation)) << 16)
1265 + (((int32)(x_red_diff * x_accumulation)) << 8)
1266 + (((int32)(x_alpha_diff * x_accumulation)));
1267 drawer->SetPixel(x,y,x_gradient);
1268 } else {
1269 drawer->SetPixel(x,y,x_target);
1270 }
1271 }
1272 }
1273 }
1274 binary_bits += binary_bpr - bytes_advanced;
1275 }
1276}
1277
1278
1279void
1280FillTool::FillGradientPreview(BitmapDrawer *drawer, BBitmap *binary_map,
1281 int32 dx, int32 dy, int32 min_x, int32 max_x, int32 min_y, int32 max_y,
1282 uint32 new_color, uint32 gradient_color)
1283{
1284 // This preview fill calculates only every other pixel.
1285 uchar *binary_bits = (uchar*)binary_map->Bits();
1286 int32 binary_bpr = binary_map->BytesPerRow();
1287
1288 uint32 x_source,x_target;
1289 uint32 y_source,y_target;
1290
1291
1292 if (dx<0)
1293 x_target = gradient_color;
1294 else
1295 x_target = new_color;
1296
1297 if (dy<0) {
1298 y_target = gradient_color;
1299 y_source = new_color;
1300 } else {
1301 y_target = new_color;
1302 y_source = gradient_color;
1303 }
1304 uint32 y_gradient;
1305 uint32 x_gradient;
1306
1307 // These might also be negative
1308 int16 x_red_diff,x_green_diff,x_blue_diff,x_alpha_diff;
1309 int16 y_red_diff,y_green_diff,y_blue_diff,y_alpha_diff;
1310
1311 float x_accumulation;
1312 float y_accumulation = 0;
1313
1314 y_gradient = y_source;
1315 uchar next_value = 0;
1316 uchar next_rows_value = 0;
1317
1318 y_red_diff = (int16)((y_target>>8) & 0xFF) - (int16)((y_source>>8) & 0xFF);
1319 y_green_diff = (int16)((y_target>>16) & 0xFF) - (int16)((y_source>>16) & 0xFF);
1320 y_blue_diff = (int16)((y_target>>24) & 0xFF) - (int16)((y_source>>24) & 0xFF);
1321 y_alpha_diff = (int16)((y_target) & 0xFF) - (int16)((y_source) & 0xFF);
1322
1323 for (int32 y = min_y; y <= max_y - 1; y+=2) {
1324 int32 bytes_advanced = 0;
1325 // Here we should move y-gradient 1 step closer to y-target
1326 // and put x-source to y-gradient. We should also recalculate
1327 // the x-gradient step.
1328 if (dy<0) {
1329 y_accumulation = (float)(abs(dy))/50.0*(float)(max_y-y)/(float)(max_y - min_y);
1330 if (y_accumulation < 1.0) {
1331 y_gradient = y_source
1332 + (((int32)(y_blue_diff * (1.0-y_accumulation))) << 24)
1333 + (((int32)(y_green_diff * (1.0-y_accumulation))) << 16)
1334 + (((int32)(y_red_diff * (1.0-y_accumulation))) << 8)
1335 + (((int32)(y_alpha_diff * (1.0-y_accumulation))));
1336 } else {
1337 y_gradient = y_source;
1338 }
1339 } else {
1340 y_accumulation = (float)dy/50.0*(float)y/(float)(max_y - min_y);
1341 if (y_accumulation < 1.0) {
1342 y_gradient = y_source
1343 + (((int32)(y_blue_diff * y_accumulation)) << 24)
1344 + (((int32)(y_green_diff * y_accumulation)) << 16)
1345 + (((int32)(y_red_diff * y_accumulation)) << 8)
1346 + (((int32)(y_alpha_diff * y_accumulation)));
1347 } else {
1348 y_gradient = y_target;
1349 }
1350 }
1351
1352 if (dx<0) {
1353 x_source = new_color;
1354 x_target = y_gradient;
1355 } else {
1356 x_source = y_gradient;
1357 x_target = new_color;
1358 }
1359
1360 x_red_diff = (int16)((x_target>>8) & 0xFF) - (int16)((x_source>>8) & 0xFF);
1361 x_green_diff = (int16)((x_target>>16) & 0xFF) - (int16)((x_source>>16) & 0xFF);
1362 x_blue_diff = (int16)((x_target>>24) & 0xFF) - (int16)((x_source>>24) & 0xFF);
1363 x_alpha_diff = (int16)((x_target) & 0xFF) - (int16)((x_source) & 0xFF);
1364
1365 x_accumulation = 0;
1366 for (int32 x=min_x;x<=max_x-1;x+=2) {
1367 // This might crash if max_x == min_x
1368 if (dx < 0)
1369 x_accumulation = (float)abs(dx)/50.0*(float)(max_x-x)/(float)(max_x - min_x);
1370 else
1371 x_accumulation = (float)dx/50.0*(float)x/(float)(max_x - min_x);
1372
1373 if ( (x % 8) == 0 ) {
1374 next_rows_value = *(binary_bits+binary_bpr);
1375 next_value = *binary_bits++;
1376 bytes_advanced++;
1377 }
1378 if ( next_value & (0x01 << (7-(x%8))) ) {
1379 // Here we should put a new value into position x,y
1380 if (dx < 0) {
1381 if (x_accumulation < 1.0) {
1382 x_gradient = x_source
1383 + (((int32)(x_blue_diff * (1.0-x_accumulation))) << 24)
1384 + (((int32)(x_green_diff * (1.0-x_accumulation))) << 16)
1385 + (((int32)(x_red_diff * (1.0-x_accumulation))) << 8)
1386 + (((int32)(x_alpha_diff * (1.0-x_accumulation))));
1387 drawer->SetPixel(x,y,x_gradient);
1388
1389 if (next_value & (0x01 << (7-((x+1)%8))))
1390 drawer->SetPixel(x+1,y,x_gradient);
1391
1392 if (next_rows_value & (0x01 << (7-(x%8))))
1393 drawer->SetPixel(x,y+1,x_gradient);
1394
1395 if (next_rows_value & (0x01 << (7-((x+1)%8))))
1396 drawer->SetPixel(x+1,y+1,x_gradient);
1397 } else {
1398 drawer->SetPixel(x,y,x_source);
1399 if (next_value & (0x01 << (7-((x+1)%8))))
1400 drawer->SetPixel(x+1,y,x_source);
1401
1402 if (next_rows_value & (0x01 << (7-(x%8))))
1403 drawer->SetPixel(x,y+1,x_source);
1404
1405 if (next_rows_value & (0x01 << (7-((x+1)%8))))
1406 drawer->SetPixel(x+1,y+1,x_source);
1407 }
1408 } else {
1409 if (x_accumulation < 1.0) {
1410 x_gradient = x_source
1411 + (((int32)(x_blue_diff * x_accumulation)) << 24)
1412 + (((int32)(x_green_diff * x_accumulation)) << 16)
1413 + (((int32)(x_red_diff * x_accumulation)) << 8)
1414 + (((int32)(x_alpha_diff * x_accumulation)));
1415 drawer->SetPixel(x,y,x_gradient);
1416
1417 if (next_value & (0x01 << (7-((x+1)%8))))
1418 drawer->SetPixel(x+1,y,x_gradient);
1419
1420 if (next_rows_value & (0x01 << (7-(x%8))))
1421 drawer->SetPixel(x,y+1,x_gradient);
1422
1423 if (next_rows_value & (0x01 << (7-((x+1)%8))))
1424 drawer->SetPixel(x+1,y+1,x_gradient);
1425 } else {
1426 drawer->SetPixel(x,y,x_target);
1427 if (next_value & (0x01 << (7-((x+1)%8))))
1428 drawer->SetPixel(x+1,y,x_target);
1429
1430 if (next_rows_value & (0x01 << (7-(x%8))))
1431 drawer->SetPixel(x,y+1,x_target);
1432
1433 if (next_rows_value & (0x01 << (7-((x+1)%8))))
1434 drawer->SetPixel(x+1,y+1,x_target);
1435 }
1436 }
1437 }
1438 }
1439 binary_bits += binary_bpr - bytes_advanced+binary_bpr;
1440 }
1441}
1442
1443
1444BRect
1445FillTool::calcBinaryMapBounds(BBitmap *boolean_map)
1446{
1447 // it seems like the monochrome-bitmap is aligned at 16-bit boundary instead
1448 // of 32-bit as the BeBook claims
1449 char *bits = (char*)boolean_map->Bits();
1450 int32 bpr = boolean_map->BytesPerRow();
1451 bool selected_line;
1452
1453 // this is an invalid rect
1454 BRect rc = BRect(100000,100000,-100000,-100000);
1455
1456 int32 height = boolean_map->Bounds().IntegerHeight();
1457 for (int32 y=0;y<=height;y++) {
1458 selected_line = FALSE0;
1459 for (int32 i=0;i<bpr;i++) {
1460 selected_line |= *bits != 0x00;
1461 if (*bits != 0x00) {
1462 for (int32 b=0;b<8;b++) {
1463 rc.left = min_c(rc.left,i*8+(((*bits>>(7-b))& 0x00000001) ? b : 100000))((rc.left)>(i*8+(((*bits>>(7-b))& 0x00000001) ? b
: 100000))?(i*8+(((*bits>>(7-b))& 0x00000001) ? b :
100000)):(rc.left))
;
1464 rc.right = max_c(rc.right,i*8+(((*bits>>(7-b))& 0x00000001) ? b : -100000))((rc.right)>(i*8+(((*bits>>(7-b))& 0x00000001) ?
b : -100000))?(rc.right):(i*8+(((*bits>>(7-b))& 0x00000001
) ? b : -100000)))
;
1465 }
1466 }
1467 ++bits;
1468 }
1469 if (selected_line) {
1470 rc.top = min_c(rc.top,y)((rc.top)>(y)?(y):(rc.top));
1471 rc.bottom = max_c(rc.bottom,y)((rc.bottom)>(y)?(rc.bottom):(y));
1472 }
1473 }
1474
1475 return rc & boolean_map->Bounds();
1476}
1477
1478
1479status_t
1480FillTool::readSettings(BFile &file,bool is_little_endian)
1481{
1482 if (DrawingTool::readSettings(file,is_little_endian) != B_OK((int)0))
1483 return B_ERROR(-1);
1484
1485 if (file.Read(&gradient_color1,sizeof(uint32)) != sizeof(uint32))
1486 return B_ERROR(-1);
1487
1488 if (file.Read(&gradient_color2,sizeof(uint32)) != sizeof(uint32))
1489 return B_ERROR(-1);
1490
1491 if (is_little_endian) {
1492 gradient_color1 = B_LENDIAN_TO_HOST_INT32(gradient_color1)(uint32)(gradient_color1);
1493 gradient_color2 = B_LENDIAN_TO_HOST_INT32(gradient_color2)(uint32)(gradient_color2);
1494 } else {
1495 gradient_color1 = B_BENDIAN_TO_HOST_INT32(gradient_color1)(uint32)__builtin_bswap32(gradient_color1);
1496 gradient_color2 = B_BENDIAN_TO_HOST_INT32(gradient_color2)(uint32)__builtin_bswap32(gradient_color2);
1497 }
1498
1499 return B_OK((int)0);
1500}
1501
1502
1503status_t
1504FillTool::writeSettings(BFile &file)
1505{
1506 if (DrawingTool::writeSettings(file) != B_OK((int)0))
1507 return B_ERROR(-1);
1508
1509 if (file.Write(&gradient_color1,sizeof(uint32)) != sizeof(uint32))
1510 return B_ERROR(-1);
1511
1512 if (file.Write(&gradient_color2,sizeof(uint32)) != sizeof(uint32))
1513 return B_ERROR(-1);
1514
1515 return B_OK((int)0);
1516
1517}
1518
1519
1520const void*
1521FillTool::ToolCursor() const
1522{
1523 return HS_FILL_CURSOR;
1524}
1525
1526
1527const char*
1528FillTool::HelpString(bool isInUse) const
1529{
1530 return (isInUse
1531 ? B_TRANSLATE("Making a fill.")BLocaleRoster::Default()->GetCatalog()->GetString(("Making a fill."
), "Tools")
1532 : B_TRANSLATE("Click to make a fill.")BLocaleRoster::Default()->GetCatalog()->GetString(("Click to make a fill."
), "Tools")
);
1533}
1534
1535
1536// #pragma mark -- GradientView
1537
1538
1539#define GRADIENT_ADJUSTED'gRad' 'gRad'
1540
1541
1542class FillToolConfigView::GradientView : public BControl {
1543public:
1544 GradientView(uint32,uint32);
1545 virtual ~GradientView();
1546
1547 virtual void AttachedToWindow();
1548 virtual void Draw(BRect);
1549 virtual void MessageReceived(BMessage*);
1550 virtual void MouseDown(BPoint);
1551 virtual void FrameResized(float newWidth, float newHeight);
1552 virtual void LayoutChanged();
1553
1554private:
1555 void _CalculateGradient();
1556
1557private:
1558 rgb_color fColor1;
1559 rgb_color fColor2;
1560
1561 BBitmap* fGradient;
1562};
1563
1564
1565FillToolConfigView::GradientView::GradientView(uint32 c1, uint32 c2)
1566 : BControl("gradient view", "Gradient", new BMessage(GRADIENT_ADJUSTED'gRad'),
1567 B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE | B_FRAME_EVENTS)
1568 , fGradient(NULL__null)
1569{
1570 fColor1 = BGRAColorToRGB(c1);
1571 fColor2 = BGRAColorToRGB(c2);
1572
1573 Message()->AddInt32("color1",RGBColorToBGRA(fColor1));
1574 Message()->AddInt32("color2",RGBColorToBGRA(fColor2));
1575
1576 SetExplicitMinSize(BSize(100.0, 20.0));
1577 SetExplicitMaxSize(BSize(B_SIZE_UNSET, 20.0));
1578}
1579
1580
1581FillToolConfigView::GradientView::~GradientView()
1582{
1583 delete fGradient;
1584}
1585
1586
1587void
1588FillToolConfigView::GradientView::AttachedToWindow()
1589{
1590 BControl::AttachedToWindow();
1591
1592 delete fGradient;
1593
1594 BRect bounds = Bounds();
1595 bounds.bottom = bounds.top;
1596 fGradient = new BBitmap(bounds, B_RGB32);
1597
1598 _CalculateGradient();
1599}
1600
1601
1602void
1603FillToolConfigView::GradientView::LayoutChanged()
1604{
1605 BControl::LayoutChanged();
1606
1607 delete fGradient;
1608
1609 BRect bounds = Bounds();
1610 bounds.bottom = bounds.top;
1611 fGradient = new BBitmap(bounds, B_RGB32);
1612
1613 _CalculateGradient();
1614}
1615
1616
1617void
1618FillToolConfigView::GradientView::Draw(BRect rect)
1619{
1620 BControl::Draw(rect);
1621
1622 SetHighColor(0, 0, 0, 255);
1623 StrokeRect(Bounds());
1624
1625 BRect bounds = Bounds();
1626 bounds.InsetBy(1.0, 1.0);
1627 DrawBitmap(fGradient, fGradient->Bounds(), bounds);
1628}
1629
1630
1631void
1632FillToolConfigView::GradientView::MessageReceived(BMessage* message)
1633{
1634 switch (message->what) {
1635 case B_PASTE: {
1636 if (message->WasDropped()) {
1637 BPoint dropPoint = ConvertFromScreen(message->DropPoint());
1638
1639 ssize_t size;
1640 const void* data;
1641 if (message->FindData("RGBColor", B_RGB_COLOR_TYPE, &data,
1642 &size) == B_OK((int)0) && size == sizeof(rgb_color)) {
1643 if (dropPoint.x < (Bounds().right / 2.0))
1644 memcpy((void*)(&fColor1), data, size);
1645 else
1646 memcpy((void*)(&fColor2), data, size);
1647
1648 Message()->ReplaceInt32("color1", RGBColorToBGRA(fColor1));
1649 Message()->ReplaceInt32("color2", RGBColorToBGRA(fColor2));
1650
1651 _CalculateGradient();
1652 Draw(Bounds());
1653 Invoke();
1654 }
1655 }
1656 } break;
1657
1658 default: {
1659 BControl::MessageReceived(message);
1660 } break;
1661 }
1662}
1663
1664
1665void
1666FillToolConfigView::GradientView::MouseDown(BPoint point)
1667{
1668 BControl::MouseDown(point);
1669
1670 rgb_color color = fColor1;
1671 if (point.x > (Bounds().right / 2.0))
1672 color = fColor2;
1673
1674 // Open the palette-view.
1675 ColorPaletteWindow::showPaletteWindow();
1676 ColorPaletteWindow::ChangePaletteColor(color);
1677}
1678
1679
1680void
1681FillToolConfigView::GradientView::FrameResized(float newWidth, float newHeight)
1682{
1683 delete fGradient;
1684 fGradient = new BBitmap(BRect(0, 0, newWidth, 0), B_RGB32);
1685
1686 _CalculateGradient();
1687}
1688
1689
1690void
1691FillToolConfigView::GradientView::_CalculateGradient()
1692{
1693 union {
1694 uint8 bytes[4];
1695 uint32 word;
1696 } c;
1697
1698 uint32 c1 = RGBColorToBGRA(fColor1);
1699 uint32 c2 = RGBColorToBGRA(fColor2);
1700
1701 uint32 *bits = (uint32*)fGradient->Bits();
1702 int32 width = fGradient->BytesPerRow() / 4;
1703
1704 for (int32 x = 0; x < width; ++x) {
1705 uint32 fixed_alpha = (1.0 - float(x) / float(width + 1.0)) * 32768;
1706 c.word = mix_2_pixels_fixed(c1, c2, fixed_alpha);
1707 float coeff = c.bytes[3] / 255.0;
1708 if ((x % 2) == 0) {
1709 c.bytes[0] = (uint8)(c.bytes[0] * coeff);
1710 c.bytes[1] = (uint8)(c.bytes[1] * coeff);
1711 c.bytes[2] = (uint8)(c.bytes[2] * coeff);
1712 } else {
1713 c.bytes[0] = (uint8)(c.bytes[0] * coeff + (1 - coeff) * 255);
1714 c.bytes[1] = (uint8)(c.bytes[1] * coeff + (1 - coeff) * 255);
1715 c.bytes[2] = (uint8)(c.bytes[2] * coeff + (1 - coeff) * 255);
1716 }
1717 *bits++ = c.word;
1718 }
1719}
1720
1721
1722// #pragma mark -- FillToolConfigView
1723
1724
1725FillToolConfigView::FillToolConfigView(DrawingTool* tool,uint32 c1, uint32 c2)
1726 : DrawingToolConfigView(tool)
1727{
1728 if (BLayout* layout = GetLayout()) {
1729 BMessage* message = new BMessage(OPTION_CHANGED);
1730 message->AddInt32("option", MODE_OPTION);
1731 message->AddInt32("value", 0x00000000);
1732 fFlodFill = new BCheckBox(B_TRANSLATE("Flood fill")BLocaleRoster::Default()->GetCatalog()->GetString(("Flood fill"
), "Tools")
,
1733 message);
1734
1735 message = new BMessage(OPTION_CHANGED);
1736 message->AddInt32("option", GRADIENT_ENABLED_OPTION);
1737 message->AddInt32("value", 0x00000000);
1738 fGradient =
1739 new BCheckBox(B_TRANSLATE("Enable gradient")BLocaleRoster::Default()->GetCatalog()->GetString(("Enable gradient"
), "Tools")
,
1740 message);
1741
1742 message = new BMessage(OPTION_CHANGED);
1743 message->AddInt32("option", PREVIEW_ENABLED_OPTION);
1744 message->AddInt32("value", 0x00000000);
1745 fPreview = new BCheckBox(B_TRANSLATE("Enable preview")BLocaleRoster::Default()->GetCatalog()->GetString(("Enable preview"
), "Tools")
,
1746 message);
1747
1748 fGradientView = new GradientView(c1, c2);
1749
1750 message = new BMessage(OPTION_CHANGED);
1751 message->AddInt32("option",TOLERANCE_OPTION);
1752 message->AddInt32("value",tool->GetCurrentValue(TOLERANCE_OPTION));
1753 fTolerance =
1754 new NumberSliderControl(B_TRANSLATE("Tolerance:")BLocaleRoster::Default()->GetCatalog()->GetString(("Tolerance:"
), "Tools")
,
1755 "0", message, 0, 100, false);
1756 fTolerance->SetValue(tool->GetCurrentValue(TOLERANCE_OPTION));
1757
1758 BGridLayout* toleranceLayout = LayoutSliderGrid(fTolerance);
1759
1760 layout->AddView(BGroupLayoutBuilder(B_VERTICAL, kWidgetSpacing)
1761 .Add(toleranceLayout)
1762 .AddStrut(kWidgetSpacing)
1763 .Add(SeparatorView(B_TRANSLATE("Mode")BLocaleRoster::Default()->GetCatalog()->GetString(("Mode"
), "Tools")
))
1764 .AddGroup(B_VERTICAL, kWidgetSpacing)
1765 .Add(fFlodFill)
1766 .SetInsets(kWidgetInset, 0.0, 0.0, 0.0)
1767 .End()
1768 .AddStrut(kWidgetSpacing)
1769 .Add(SeparatorView(B_TRANSLATE("Options")BLocaleRoster::Default()->GetCatalog()->GetString(("Options"
), "Tools")
))
1770 .AddGroup(B_VERTICAL, kWidgetSpacing)
1771 .Add(fGradient)
1772 .Add(fPreview)
1773 .Add(fGradientView)
1774 .SetInsets(kWidgetInset, 0.0, 0.0, 0.0)
1775 .End()
1776 .TopView()
1777 );
1778
1779 fFlodFill->SetValue(tool->GetCurrentValue(MODE_OPTION));
1780
1781 if (tool->GetCurrentValue(GRADIENT_ENABLED_OPTION) != B_CONTROL_OFF)
1782 fGradient->SetValue(B_CONTROL_ON);
1783
1784 if (tool->GetCurrentValue(PREVIEW_ENABLED_OPTION) != B_CONTROL_OFF)
1785 fPreview->SetValue(B_CONTROL_ON);
1786 }
1787}
1788
1789
1790void
1791FillToolConfigView::AttachedToWindow()
1792{
1793 DrawingToolConfigView::AttachedToWindow();
1794
1795 fFlodFill->SetTarget(this);
1796 fGradient->SetTarget(this);
1797 fPreview->SetTarget(this);
1798 fGradientView->SetTarget(this);
1799 fTolerance->SetTarget(this);
1800}
1801
1802
1803void
1804FillToolConfigView::MessageReceived(BMessage *message)
1805{
1806 switch (message->what) {
1807 case GRADIENT_ADJUSTED'gRad': {
1808 uint32 color1;
1809 uint32 color2;
1810 message->FindInt32("color1", (int32*)&color1);
1811 message->FindInt32("color2", (int32*)&color2);
1812 (dynamic_cast<FillTool*> (Tool()))->SetGradient(color1, color2);
1813 } break;
1814
1815 default: {
1816 DrawingToolConfigView::MessageReceived(message);
1817 } break;
1818 }
1819}
1820