1//
2//  PXRectangularSelectionTool.m
3//  Pixen-XCode
4//
5//  Created by Joe Osborn on Sun Jan 04 2004.
6//  Copyright (c) 2004 Open Sword Group. All rights reserved.
7//
8
9#import "PXRectangularSelectionTool.h"
10#import "PXCanvasController.h"
11#import "PXCanvas.h"
12#import "PXCanvasView.h"
13#import "PXLayer.h"
14#import "PXSelectionLayer.h"
15#import "PXToolSwitcher.h"
16
17@implementation PXRectangularSelectionTool
18
19- (NSString *)name
20{
21	return NSLocalizedString(@"RECTANGULARSELECTION_NAME", @"Rectangular Selection Tool");
22}
23
24- movingActionName
25{
26	return NSLocalizedString(@"MOVE_ACTION", @"Moving");
27}
28
29- actionName
30{
31	return NSLocalizedString(@"RECTANGULARSELECTION_ACTION", @"Selection");
32}
33
34- (BOOL)shiftKeyDown
35{
36	if (!isClicking)
37	{
38		isAdding = YES;
39		[switcher setIcon:[NSImage imageNamed:@"squareselectadd"] forTool:self];
40	}
41	return YES;
42}
43
44- (BOOL)shiftKeyUp
45{
46	if (!isClicking)
47	{
48		isAdding = NO;
49		[switcher setIcon:[NSImage imageNamed:@"squareselect"] forTool:self];
50	}
51	return YES;
52}
53
54- (BOOL)optionKeyDown
55{
56	if (!isClicking)
57	{
58		isSubtracting = YES;
59		[switcher setIcon:[NSImage imageNamed:@"squareselectsubtract"] forTool:self];
60	}
61	return YES;
62}
63
64- (BOOL)optionKeyUp
65{
66	if (!isClicking)
67	{
68		isSubtracting = NO;
69		[switcher setIcon:[NSImage imageNamed:@"squareselect"] forTool:self];
70	}
71	return YES;
72}
73
74- (void)mouseDownAt:(NSPoint)aPoint fromCanvasController:controller
75{
76	if (isSubtracting && ![[controller canvas] hasSelection]) { return; }
77
78	isClicking = YES;
79    origin = aPoint;
80
81	[[self undoManager] beginUndoGrouping];
82	[self setLayers:[[[controller canvas] layers] deepMutableCopy] fromLayers:[[controller canvas] layers] ofCanvas:[controller canvas]];
83
84	if([[controller canvas] pointIsSelected:aPoint] && (!isAdding && !isSubtracting))
85	{
86		lastSelectedRect = [[controller canvas] selectedRect];
87		[self startMovingCanvas:[controller canvas]];
88	}
89	else
90	{
91		if (!isAdding && !isSubtracting)
92		{
93			[[controller canvas] deselect];
94			oldLayerIndex = [[[controller canvas] layers] indexOfObject:[[controller canvas] activeLayer]];
95			oldLastLayerIndex = [[[controller canvas] layers] indexOfObject:[[controller canvas] lastActiveLayer]];
96			selectedRect = NSZeroRect;
97		}
98		else
99		{
100			if (oldLastLayerIndex != NSNotFound)
101			{
102				[[controller canvas] restoreActivateLayer:[[[controller canvas] layers] objectAtIndex:oldLayerIndex] lastActiveLayer:[[[controller canvas] layers] objectAtIndex:oldLastLayerIndex]];
103			}
104			else
105			{
106				[[controller canvas] restoreActivateLayer:[[[controller canvas] layers] objectAtIndex:oldLayerIndex] lastActiveLayer:nil];
107			}
108		}
109		[[controller canvas] changedInRect:NSMakeRect(lastSelectedRect.origin.x-2, lastSelectedRect.origin.y-2, lastSelectedRect.size.width+4, lastSelectedRect.size.height+4)];
110		lastSelectedRect = NSZeroRect;
111	}
112
113	if (isSubtracting)
114		[[[[controller canvas] layers] lastObject] setIsSubtracting:YES];
115}
116
117- (void)setLayers:layers fromLayers:oldLayers ofCanvas:canvas
118{
119	[[[self undoManager] prepareWithInvocationTarget:self] setLayers:oldLayers fromLayers:layers ofCanvas:canvas];
120	[canvas setLayers:layers];
121	lastSelectedRect = NSZeroRect;
122}
123
124- (void)startMovingCanvas:canvas
125{
126	[[self undoManager] setActionName:[self movingActionName]];
127	isMoving = YES;
128}
129
130- (void)stopMovingCanvas:canvas
131{
132	isMoving = NO;
133	selectedRect = lastSelectedRect;
134	[[canvas activeLayer] finalizeMotion];
135}
136
137- (void)refreshRect:(NSRect)rectangle inView:view
138{
139	NSRect modifiedRect = rectangle;
140	modifiedRect.origin.x -= 1;
141	modifiedRect.origin.y -= 1;
142	modifiedRect.size.width += 2;
143	modifiedRect.size.height += 2;
144	[view displayRect:[view convertFromCanvasToViewRect:modifiedRect]];
145}
146
147- (void)mouseDraggedFrom:(NSPoint)initialPoint to:(NSPoint)finalPoint fromCanvasController:(PXCanvasController *)controller
148{
149	if (isSubtracting && ![[controller canvas] hasSelection]) { return; }
150
151	if(isMoving)
152	{
153		[[[controller canvas] activeLayer] translateXBy:(finalPoint.x - initialPoint.x) yBy:(finalPoint.y - initialPoint.y)];
154		[[controller canvas] changedInRect:NSMakeRect(0,0,[[controller canvas] size].width,[[controller canvas] size].height)];
155	}
156	else
157	{
158		[[self undoManager] setActionName:[self actionName]];
159		int i, j;
160		for(i = lastSelectedRect.origin.x; i < NSMaxX(lastSelectedRect); i++)
161		{
162			for(j = lastSelectedRect.origin.y; j < NSMaxY(lastSelectedRect); j++)
163			{
164				[[controller canvas] deselectPixelAtPoint:NSMakePoint(i, j)];
165			}
166		}
167		selectedRect = NSIntersectionRect(NSUnionRect(NSMakeRect(origin.x, origin.y, 1, 1), NSMakeRect(finalPoint.x, finalPoint.y, 1, 1)), NSMakeRect(0, 0, [[controller canvas] size].width, [[controller canvas] size].height));
168		if(!NSEqualPoints(origin, finalPoint))
169		{
170			int i, j;
171			for(i = selectedRect.origin.x; i < NSMaxX(selectedRect); i++)
172			{
173				for(j = selectedRect.origin.y; j < NSMaxY(selectedRect); j++)
174				{
175					[[controller canvas] selectPixelAtPoint:NSMakePoint(i, j)];
176				}
177			}
178			//selectedRect = [[controller canvas] selectedRect];
179			//selectedRect = NSMakeRect(0,0,[[controller canvas] size].width,[[controller canvas] size].height);
180
181			// really ugly code!
182			// DO NOT READ BELOW THIS LINE IF YOU WISH TO RETAIN YOUR SANITY
183
184			NSRect shortVerticalDirty, longVerticalDirty, shortHorizontalDirty, longHorizontalDirty, lastVerticalDirty, lastHorizontalDirty; // phew
185
186			if (NSEqualPoints(selectedRect.origin, lastSelectedRect.origin)) { // quadrant I
187				// ------- 4 --
188				// |          |
189				// 1          2
190				// ...6...    |
191				// :     5    |
192				// :.....:_3__|
193
194				// 1)
195				shortVerticalDirty = NSMakeRect(selectedRect.origin.x, selectedRect.origin.y + MIN(lastSelectedRect.size.height, selectedRect.size.height),
196												1, fabs(selectedRect.size.height - lastSelectedRect.size.height) + 1);
197				// 2)
198				longVerticalDirty = NSMakeRect(selectedRect.origin.x + selectedRect.size.width, selectedRect.origin.y,
199											   1, selectedRect.size.height + 1);
200				// 3)
201				shortHorizontalDirty = NSMakeRect(selectedRect.origin.x + MIN(lastSelectedRect.size.width, selectedRect.size.width), selectedRect.origin.y,
202												fabs(selectedRect.size.width - lastSelectedRect.size.width) + 1, 1);
203				// 4)
204				longHorizontalDirty = NSMakeRect(selectedRect.origin.x, selectedRect.origin.y + selectedRect.size.height,
205											   selectedRect.size.width + 1, 1);
206				// 5)
207				lastVerticalDirty = NSMakeRect(selectedRect.origin.x + lastSelectedRect.size.width, selectedRect.origin.y,
208											   1, lastSelectedRect.size.height + 1);
209				// 6)
210				lastHorizontalDirty = NSMakeRect(selectedRect.origin.x, selectedRect.origin.y + lastSelectedRect.size.height,
211											   lastSelectedRect.size.width + 1, 1);
212
213			} else if (selectedRect.origin.x + selectedRect.size.width == lastSelectedRect.origin.x + lastSelectedRect.size.width &&
214					   selectedRect.origin.y == lastSelectedRect.origin.y) { // quadrant II
215				// ------- 4 --
216				// |          |
217				// 2          1
218				// |    ...6...
219				// |    5     :
220				// |__3_:.....:
221
222				// 1)
223				shortVerticalDirty = NSMakeRect(selectedRect.origin.x + selectedRect.size.width, selectedRect.origin.y + MIN(lastSelectedRect.size.height, selectedRect.size.height),
224												1, fabs(selectedRect.size.height - lastSelectedRect.size.height) + 1);
225				// 2)
226				longVerticalDirty = NSMakeRect(selectedRect.origin.x, selectedRect.origin.y,
227											   1, selectedRect.size.height + 1);
228				// 3)
229				shortHorizontalDirty = NSMakeRect(selectedRect.origin.x + MIN(selectedRect.size.width - lastSelectedRect.size.width, 0), selectedRect.origin.y,
230												  fabs(selectedRect.size.width - lastSelectedRect.size.width) + 1, 1);
231				// 4)
232				longHorizontalDirty = NSMakeRect(selectedRect.origin.x, selectedRect.origin.y + selectedRect.size.height,
233												 selectedRect.size.width + 1, 1);
234				// 5)
235				lastVerticalDirty = NSMakeRect(selectedRect.origin.x + selectedRect.size.width - lastSelectedRect.size.width, selectedRect.origin.y,
236											   1, lastSelectedRect.size.height + 1);
237				// 6)
238				lastHorizontalDirty = NSMakeRect(selectedRect.origin.x + selectedRect.size.width - lastSelectedRect.size.width, selectedRect.origin.y + lastSelectedRect.size.height,
239												 lastSelectedRect.size.width + 1, 1);
240
241
242			} else if (selectedRect.origin.x + selectedRect.size.width == lastSelectedRect.origin.x + lastSelectedRect.size.width &&
243					   selectedRect.origin.y + selectedRect.size.height == lastSelectedRect.origin.y + lastSelectedRect.size.height) { // quadrant III
244				// - 3 -.......
245				// |	5     :
246				// 2	:..6..:
247				// |          |
248				// |          1
249				// |__4_______|
250
251				// 1)
252				shortVerticalDirty = NSMakeRect(selectedRect.origin.x + selectedRect.size.width, selectedRect.origin.y + MIN(selectedRect.size.height - lastSelectedRect.size.height, 0),
253												1, fabs(selectedRect.size.height - lastSelectedRect.size.height) + 1);
254				// 2)
255				longVerticalDirty = NSMakeRect(selectedRect.origin.x, selectedRect.origin.y,
256											   1, selectedRect.size.height + 1);
257				// 3)
258				shortHorizontalDirty = NSMakeRect(selectedRect.origin.x + MIN(selectedRect.size.width - lastSelectedRect.size.width, 0), selectedRect.origin.y  + selectedRect.size.height,
259												  fabs(selectedRect.size.width - lastSelectedRect.size.width) + 1, 1);
260				// 4)
261				longHorizontalDirty = NSMakeRect(selectedRect.origin.x, selectedRect.origin.y,
262												 selectedRect.size.width + 1, 1);
263				// 5)
264				lastVerticalDirty = NSMakeRect(selectedRect.origin.x + selectedRect.size.width - lastSelectedRect.size.width, selectedRect.origin.y + selectedRect.size.height - lastSelectedRect.size.height,
265											   1, lastSelectedRect.size.height + 1);
266				// 6)
267				lastHorizontalDirty = NSMakeRect(selectedRect.origin.x + selectedRect.size.width - lastSelectedRect.size.width, selectedRect.origin.y + selectedRect.size.height - lastSelectedRect.size.height,
268												 lastSelectedRect.size.width + 1, 1);
269
270
271			} else if (selectedRect.origin.x == lastSelectedRect.origin.x &&
272					   selectedRect.origin.y + selectedRect.size.height == lastSelectedRect.origin.y + lastSelectedRect.size.height) { // quadrant IV
273				// .......- 3 -
274				// :	 5    |
275				// :..6..:    |
276				// |          |
277				// 1          2
278				// |________4_|
279
280				// 1)
281				shortVerticalDirty = NSMakeRect(selectedRect.origin.x, selectedRect.origin.y + MIN(selectedRect.size.height - lastSelectedRect.size.height, 0),
282												1, fabs(selectedRect.size.height - lastSelectedRect.size.height) + 1);
283				// 2)
284				longVerticalDirty = NSMakeRect(selectedRect.origin.x + selectedRect.size.width, selectedRect.origin.y,
285											   1, selectedRect.size.height + 1);
286				// 3)
287				shortHorizontalDirty = NSMakeRect(selectedRect.origin.x + MIN(lastSelectedRect.size.width, selectedRect.size.width), selectedRect.origin.y + selectedRect.size.height,
288												  fabs(selectedRect.size.width - lastSelectedRect.size.width) + 1, 1);
289				// 4)
290				longHorizontalDirty = NSMakeRect(selectedRect.origin.x, selectedRect.origin.y,
291												 selectedRect.size.width + 1, 1);
292				// 5)
293				lastVerticalDirty = NSMakeRect(selectedRect.origin.x + lastSelectedRect.size.width, selectedRect.origin.y + selectedRect.size.height - lastSelectedRect.size.height,
294											   1, lastSelectedRect.size.height + 1);
295				// 6)
296				lastHorizontalDirty = NSMakeRect(selectedRect.origin.x, selectedRect.origin.y + selectedRect.size.height - lastSelectedRect.size.height,
297												 lastSelectedRect.size.width + 1, 1);
298			} else { // TRANSITION OMG
299				// ?
300				lastHorizontalDirty = NSZeroRect;
301				lastVerticalDirty = NSZeroRect;
302				shortVerticalDirty = NSUnionRect(NSMakeRect(selectedRect.origin.x, selectedRect.origin.y, 1, selectedRect.size.height),
303												 NSMakeRect(lastSelectedRect.origin.x, lastSelectedRect.origin.y, 1, lastSelectedRect.size.height));
304
305				shortHorizontalDirty = NSUnionRect(NSMakeRect(selectedRect.origin.x, selectedRect.origin.y, selectedRect.size.width, 1),
306												 NSMakeRect(lastSelectedRect.origin.x, lastSelectedRect.origin.y, lastSelectedRect.size.width, 1));
307
308				longVerticalDirty = NSUnionRect(NSMakeRect(selectedRect.origin.x + selectedRect.size.width, selectedRect.origin.y, 1, selectedRect.size.height),
309												NSMakeRect(lastSelectedRect.origin.x + lastSelectedRect.size.width, lastSelectedRect.origin.y, 1, lastSelectedRect.size.height));
310
311				longHorizontalDirty = NSUnionRect(NSMakeRect(selectedRect.origin.x, selectedRect.origin.y + selectedRect.size.height, selectedRect.size.width, 1),
312												   NSMakeRect(lastSelectedRect.origin.x, lastSelectedRect.origin.y + lastSelectedRect.size.height, lastSelectedRect.size.width, 1));
313			}
314
315			if (lastVerticalDirty.size.height >= 1) {
316				[self refreshRect:lastVerticalDirty inView:[controller view]];
317			}
318			if (lastHorizontalDirty.size.width >= 1) {
319				[self refreshRect:lastHorizontalDirty inView:[controller view]];
320			}
321			[self refreshRect:longVerticalDirty inView:[controller view]];
322			[self refreshRect:longHorizontalDirty inView:[controller view]];
323			[self refreshRect:shortVerticalDirty inView:[controller view]];
324			[self refreshRect:shortHorizontalDirty inView:[controller view]];
325
326			lastSelectedRect = selectedRect;
327		}
328	}
329}
330
331- (void)mouseUpAt:(NSPoint)aPoint fromCanvasController:controller
332{
333	if (isSubtracting && ![[controller canvas] hasSelection]) { return; }
334
335	isClicking = NO;
336	if(isMoving)
337	{
338		[self stopMovingCanvas:[controller canvas]];
339	}
340	else if(NSEqualPoints(origin, aPoint))
341	{
342		NSRect deselectRect = [[controller canvas] selectedRect];
343		[[controller canvas] deselect];
344		[[controller canvas] changedInRect:NSMakeRect(deselectRect.origin.x-2, deselectRect.origin.y-2, deselectRect.size.width+4, deselectRect.size.height+4)];
345	}
346	else
347	{
348		NSRect changeRect = [[controller canvas] selectedRect];
349
350		if (isSubtracting)
351		{
352			int i, j;
353			for (i = lastSelectedRect.origin.x; i < NSMaxX(lastSelectedRect); i++)
354			{
355				for (j = lastSelectedRect.origin.y; j < NSMaxY(lastSelectedRect); j++)
356				{
357					NSPoint point = NSMakePoint(i, j);
358					[[controller canvas] deselectPixelAtPoint:point];
359					if ([[controller canvas] pointIsSelected:point])
360					{
361						[[controller canvas] setColor:[[[[controller canvas] layers] lastObject] colorAtPoint:point] atPoint:point];
362					}
363					[[[[controller canvas] layers] lastObject] setColor:nil atPoint:point];
364
365				}
366			}
367			[[[[controller canvas] layers] lastObject] finalize];
368			[[controller canvas] activateLayer:[[[controller canvas] layers] lastObject]];
369			changeRect = NSUnionRect(changeRect, lastSelectedRect);
370		}
371		else
372			[[controller canvas] finalizeSelection];
373		changeRect.size.width++;
374		changeRect.size.height++;
375		[[controller canvas] changedInRect:changeRect];
376	}
377
378	if (isSubtracting && !(NSEqualPoints(origin, aPoint)))
379		[[[[controller canvas] layers] lastObject] setIsSubtracting:NO];
380
381	[[self undoManager] endUndoGrouping];
382}
383
384@end
385