1// 2// PXFillTool.m 3// Pixen-XCode 4// 5// Created by Joe Osborn on Tue Nov 18 2003. 6// Copyright (c) 2003 Open Sword Group. All rights reserved. 7// 8 9// This code is based on some from Will Leshner. Thanks, man! 10 11#import "PXFillTool.h" 12#import "PXCanvas.h" 13#import "PXCanvasController.h" 14#import "PXPoint.h" 15 16@implementation PXFillTool 17 18- (NSString *)name 19{ 20 return NSLocalizedString(@"FILL_NAME", @"Fill Tool"); 21} 22 23- actionName 24{ 25 return NSLocalizedString(@"FILL_ACTION", @"Fill"); 26} 27 28- color 29{ 30 return color; 31} 32 33- (void)setColor:aColor 34{ 35 color = aColor; 36} 37 38- (BOOL)shouldAbandonFillingAtPoint:(NSPoint)aPoint fromCanvasController:controller 39{ 40 if([[self color] isEqual:[[controller canvas] colorAtPoint:aPoint]]) { return YES; } 41 //this is all to dodge the clear-on-clear bug. 42 if([[self color] alphaComponent] < .00125) 43 { 44 if([[controller canvas] colorAtPoint:aPoint] == nil) { return YES; } 45 if([[[controller canvas] colorAtPoint:aPoint] alphaComponent] < .00125) { return YES; } 46 } 47 return NO; 48} 49 50- (void)mouseDownAt:(NSPoint)aPoint fromCanvasController:controller 51{ 52 if([self shouldAbandonFillingAtPoint:aPoint fromCanvasController:controller]) { return; } 53 [[self undoManager] setActionName:[self actionName]]; 54 [[self undoManager] beginUndoGrouping]; 55 [[[NSDocumentController sharedDocumentController] currentDocument] updateChangeCount:NSChangeDone]; 56 [self fillAtPoint:aPoint inCanvas:[controller canvas] replacingColor:[[controller canvas] colorAtPoint:aPoint] withColor:[self color]]; 57 if([[self undoManager] groupingLevel] != 0) { [[self undoManager] endUndoGrouping]; } 58} 59 60- (void)registerUndoForReplacingColor:oldColor withColor:newColor atPoints:points inLayer:aLayer ofCanvas:aCanvas 61{ 62 [[[self undoManager] prepareWithInvocationTarget:self] replaceColor:newColor withColor:oldColor atPoints:points inLayer:aLayer ofCanvas:aCanvas]; 63 [[[self undoManager] prepareWithInvocationTarget:aCanvas] changedInRect:NSMakeRect(0, 0, [aCanvas size].width, [aCanvas size].height)]; 64} 65 66- (void)replaceColor:oldColor withColor:newColor atPoints:points inLayer:aLayer ofCanvas:aCanvas 67{ 68 if([[self undoManager] isUndoing] || [[self undoManager] isRedoing]) { [self registerUndoForReplacingColor:oldColor withColor:newColor atPoints:points inLayer:aLayer ofCanvas:aCanvas]; } 69 [aLayer setColor:newColor atPoints:points]; 70} 71 72- (BOOL)point:(NSPoint)aPoint isUsefulForReplacing:oldColor inCanvas:aCanvas shouldCheckToTheLeft:(BOOL)check 73{ 74 return 75 ([[NSUserDefaults standardUserDefaults] boolForKey:@"PXShouldTile"] ? YES : (aPoint.y < [aCanvas size].height)) && 76 ([[NSUserDefaults standardUserDefaults] boolForKey:@"PXShouldTile"] ? YES : (aPoint.y >= 0)) && 77 ([[aCanvas colorAtPoint:aPoint] isEqual:oldColor] && 78 (check ? ![[aCanvas colorAtPoint:NSMakePoint(aPoint.x-1, aPoint.y)] isEqual:oldColor] : YES) && 79 ([aCanvas canDrawAtPoint:aPoint])); 80} 81 82- (void)lookAround:(NSPoint)currentPoint inCanvas:aCanvas replacingColor:oldColor shouldCheckToTheLeft:(BOOL)check newPointsInto:points 83{ 84 NSPoint upPoint = NSMakePoint(currentPoint.x, currentPoint.y+1); 85 if([self point:upPoint isUsefulForReplacing:oldColor inCanvas:aCanvas shouldCheckToTheLeft:check]) 86 { 87 [points addObject:[PXPoint withNSPoint:upPoint]]; 88 } 89 NSPoint downPoint = NSMakePoint(currentPoint.x, currentPoint.y-1); 90 if([self point:downPoint isUsefulForReplacing:oldColor inCanvas:aCanvas shouldCheckToTheLeft:check]) 91 { 92 [points addObject:[PXPoint withNSPoint:downPoint]]; 93 } 94} 95 96- (NSPoint)leftmostValidPointInRowOf:(NSPoint)point replacingColor:oldColor inCanvas:aCanvas 97{ 98 NSPoint leftmost = point; 99 int columnsChecked = 0; 100 while(([[NSUserDefaults standardUserDefaults] boolForKey:@"PXShouldTile"] ? (columnsChecked < [aCanvas size].width) : leftmost.x >= 0) && 101 [[aCanvas colorAtPoint:NSMakePoint(leftmost.x-1, leftmost.y)] isEqual:oldColor]) 102 { 103 leftmost.x--; 104 columnsChecked++; 105 } 106 return leftmost; 107} 108 109- drawLineStartingAtPoint:(NSPoint)currentPoint inCanvas:aCanvas replacingColor:oldColor withColor:newColor newPointsInto:points 110{ 111 id thisTimeFilled = [[[NSMutableArray alloc] initWithCapacity:2048] autorelease]; 112 [self lookAround:currentPoint inCanvas:aCanvas replacingColor:oldColor shouldCheckToTheLeft:NO newPointsInto:points]; 113 int columnsChecked = 0; 114 while(([[NSUserDefaults standardUserDefaults] boolForKey:@"PXShouldTile"] ? (columnsChecked < [aCanvas size].width) : currentPoint.x < [aCanvas size].width) && [[aCanvas colorAtPoint:currentPoint] isEqual:oldColor]) 115 { 116 [self lookAround:currentPoint inCanvas:aCanvas replacingColor:oldColor shouldCheckToTheLeft:YES newPointsInto:points]; 117 if([aCanvas canDrawAtPoint:currentPoint]) { [thisTimeFilled addObject:[PXPoint withNSPoint:currentPoint]]; } 118 currentPoint.x++; 119 columnsChecked++; 120 } 121 [self activatePointWithOldColor:oldColor newColor:newColor atPoints:thisTimeFilled ofCanvas:aCanvas]; 122 return thisTimeFilled; 123} 124 125- (void)activatePointWithOldColor:oldColor newColor:newColor atPoints:thisTimeFilled ofCanvas:aCanvas 126{ 127 [self replaceColor:oldColor withColor:newColor atPoints:thisTimeFilled inLayer:[aCanvas activeLayer] ofCanvas:aCanvas]; 128} 129 130- (void)fillAtPoint:(NSPoint)aPoint inCanvas:aCanvas replacingColor:oldColor withColor:newColor 131{ 132 id points = [[[NSMutableArray alloc] initWithCapacity:50000] autorelease]; 133 id filledPoints = [[[NSMutableArray alloc] initWithCapacity:50000] autorelease]; 134 [points addObject:[PXPoint withNSPoint:aPoint]]; 135 while([points count] > 0) 136 { 137 NSPoint current = [[points lastObject] pointValue]; 138 [points removeLastObject]; 139 [filledPoints addObjectsFromArray: 140 [self drawLineStartingAtPoint:[self leftmostValidPointInRowOf:current replacingColor:oldColor inCanvas:aCanvas] 141 inCanvas:aCanvas 142 replacingColor:oldColor 143 withColor:newColor 144 newPointsInto:points]]; 145 } 146 [aCanvas changedInRect:NSMakeRect(0, 0, [aCanvas size].width, [aCanvas size].height)]; 147 [self registerUndoForReplacingColor:oldColor withColor:newColor atPoints:filledPoints inLayer:[aCanvas activeLayer] ofCanvas:aCanvas]; 148} 149 150@end 151