1//  PXCanvasView.m
2//  Pixen
3//
4//  Created by Joe Osborn on Sat Sep 13 2003.
5//  Copyright (c) 2003 Open Sword Group. All rights reserved.
6//
7
8#import "PXCanvasView.h"
9#import "PXCanvas.h"
10#import "PXBackground.h"
11#import "PXBackgroundController.h"
12#import "PXToolPaletteController.h"
13#import "PXToolSwitcher.h"
14#import "PXEyedropperTool.h"
15#import "PXInfoPanelController.h"
16#import "PXGrid.h"
17#import "PXCrosshair.h"
18
19//Taken from a man calling himself "BROCK BRANDENBERG" who is here to save the day.
20#import "SBCenteringClipView.h"
21
22#ifndef __COCOA__
23#include "math.h"
24#endif
25
26
27
28@implementation PXCanvasView
29
30- (void)rightMouseDown:event
31{
32    [delegate rightMouseDown:event];
33}
34
35- (void)setDelegate:aDelegate
36{
37    delegate = aDelegate;
38}
39
40- initWithFrame:(NSRect)rect
41{
42    [super initWithFrame:rect];
43    zoomPercentage = 100;
44    shouldDrawMainBackground = YES;
45    trackingRect = -1;
46	grid = [[PXGrid alloc] initWithUnitSize:NSMakeSize(1,1) color:[NSColor blackColor] shouldDraw:NO];
47	crosshair = [[PXCrosshair alloc] init];
48    return self;
49}
50
51- (void)dealloc
52{
53	[crosshair release];
54	[grid release];
55    [mainBackground release];
56    [alternateBackground release];
57    [super dealloc];
58}
59
60- (void)setCrosshair:aCrosshair
61{
62	[crosshair release];
63	crosshair = [aCrosshair retain];
64}
65
66- (void)setMainBackground:aBackground
67{
68	[aBackground retain];
69	[mainBackground release];
70	mainBackground = aBackground;
71	[self setNeedsDisplayInRect:[self visibleRect]];
72}
73
74- (void)setAlternateBackground:aBackground
75{
76    [aBackground retain];
77    [alternateBackground release];
78    alternateBackground = aBackground;
79    [self setNeedsDisplayInRect:[self visibleRect]];
80}
81
82- tiledRectsAroundRect:(NSRect)initial
83{
84	id array = [NSMutableArray arrayWithCapacity:9];
85	NSRect current = initial;
86	id transformation = [self setupTransform];
87	NSSize size = [transformation transformSize:[canvas size]];
88	[array addObject:[NSValue valueWithRect:current]];
89	current.origin.x -= size.width;
90	[array addObject:[NSValue valueWithRect:current]];
91	current.origin.y += size.height;
92	[array addObject:[NSValue valueWithRect:current]];
93	current.origin.x += size.width;
94	[array addObject:[NSValue valueWithRect:current]];
95	current.origin.x += size.width;
96	[array addObject:[NSValue valueWithRect:current]];
97	current.origin.y -= size.height;
98	[array addObject:[NSValue valueWithRect:current]];
99	current.origin.y -= size.height;
100	[array addObject:[NSValue valueWithRect:current]];
101	current.origin.x -= size.width;
102	[array addObject:[NSValue valueWithRect:current]];
103	current.origin.x -= size.width;
104	[array addObject:[NSValue valueWithRect:current]];
105	return array;
106}
107
108- (void)refreshTiles:sender
109{
110	NSRect srcRect = [[[timer userInfo] objectForKey:@"rect"] rectValue];
111	id enumerator = [[self tiledRectsAroundRect:[self convertFromCanvasToViewRect:srcRect]] objectEnumerator];
112	id current;
113	while(current = [enumerator nextObject])
114	{
115		[self setNeedsDisplayInRect:[current rectValue]];
116	}
117}
118
119- (void)setNeedsDisplayInCanvasRect:(NSRect)rect
120{
121	if([self shouldTile] && ((timer == nil) || ![timer isValid]))
122	{
123		[timer release];
124		timer = [[NSTimer scheduledTimerWithTimeInterval:0.05 target:self selector:@selector(refreshTiles:) userInfo:[NSDictionary dictionaryWithObject:[NSValue valueWithRect:NSMakeRect(rect.origin.x-20, rect.origin.y-20, rect.size.width+40, rect.size.height+40)] forKey:@"rect"] repeats:NO] retain];
125	}
126	[self setNeedsDisplayInRect:[self convertFromCanvasToViewRect:rect]];
127}
128
129- (void)setCanvas:aCanvas
130{
131    canvas = aCanvas;
132	[grid setUnitSize:[aCanvas gridUnitSize]];
133	[grid setColor:[aCanvas gridColor]];
134	[grid setShouldDraw:[aCanvas gridShouldDraw]];
135    [self sizeToCanvas];
136}
137
138- (NSRect)convertFromViewToCanvasRect:(NSRect)viewRect
139{
140	id transformation = [self setupTransform];
141	[transformation invert];
142	NSPoint floored = [self convertFromViewToCanvasPoint:viewRect.origin];
143	NSSize ceiled = [transformation transformSize:viewRect.size];
144	ceiled.width += 1;
145	ceiled.height += 1;
146	return NSMakeRect(floored.x, floored.y, ceiled.width, ceiled.height);
147}
148
149- (NSPoint)convertFromCanvasToViewPoint:(NSPoint)point
150{
151	id transformation = [self setupTransform];
152	return [transformation transformPoint:point];
153}
154
155- (NSRect)convertFromCanvasToViewRect:(NSRect)rect
156{
157	id transformation = [self setupTransform];
158	NSPoint origin = [transformation transformPoint:rect.origin];
159	NSSize size = [transformation transformSize:rect.size];
160	return NSMakeRect(origin.x, origin.y, size.width, size.height);
161}
162
163- (NSPoint)convertFromViewToCanvasPoint:(NSPoint)point
164{
165	id transformation = [self setupTransform];
166	[transformation invert];
167	NSPoint floored = [transformation transformPoint:point];
168	floored.x = floorf(floored.x);
169	floored.y = floorf(floored.y);
170	return floored;
171}
172
173- (NSPoint)convertFromWindowToCanvasPoint:(NSPoint)location
174{
175	return [self convertFromViewToCanvasPoint:[self convertPoint:location fromView:nil]];
176}
177
178- (void)centerOn:(NSPoint)aPoint
179{
180    if(![[self superview] isKindOfClass:[NSClipView class]]) { return; }
181    NSRect clipFrame = [[self superview] frame];
182    [self scrollPoint:NSMakePoint(aPoint.x - clipFrame.size.width/2.0, aPoint.y - clipFrame.size.height/2.0)];
183    centeredPoint = [self convertFromViewToCanvasPoint:aPoint];
184}
185
186- (BOOL)shouldTile
187{
188	id transformation = [self setupScaleTransform];
189	return [[NSUserDefaults standardUserDefaults] boolForKey:@"PXShouldTile"] && (([transformation transformSize:[canvas size]].width < [[self superview] frame].size.width) && ([transformation transformSize:[canvas size]].height < [[self superview] frame].size.height)) && (([canvas size].width <= 256) && ([canvas size].height <= 256));
190}
191
192- (void)setShouldTile:(BOOL)newShouldTile
193{
194	shouldTile = newShouldTile;
195	[self sizeToCanvas];
196}
197
198- (void)toggleShouldTile
199{
200	[self setShouldTile:!shouldTile];
201}
202
203- (void)sizeToCanvas
204{
205
206    if(NSEqualSizes([canvas size], NSZeroSize))
207	{
208		return;
209	}
210    transform = [self setupTransform];
211    [self setFrameSize:NSMakeSize([transform transformSize:[canvas size]].width, [transform transformSize:[canvas size]].height)];
212
213    if([self shouldTile])
214	{
215		[self setFrameSize:NSMakeSize([self frame].size.width * 3, [self frame].size.height * 3)];
216	}
217    [self centerOn:[self convertFromCanvasToViewPoint:centeredPoint]];
218    [[self window] invalidateCursorRectsForView:self];
219    [self setNeedsDisplay:YES];
220}
221
222- (float)zoomPercentage
223{
224    return zoomPercentage;
225}
226
227- (void)setZoomPercentage:(float)percent
228{
229    centeredPoint = [self convertFromViewToCanvasPoint:NSMakePoint([self visibleRect].origin.x + [self visibleRect].size.width/2, [self visibleRect].origin.y + [self visibleRect].size.height/2)];
230    zoomPercentage = percent;
231    [self sizeToCanvas];
232}
233
234- (BOOL)shouldDrawMainBackground
235{
236    return shouldDrawMainBackground;
237}
238
239- (void)setShouldDrawMainBackground:(BOOL)newShouldDrawBG
240{
241	if(mainBackground != alternateBackground && alternateBackground != nil)
242    {
243		shouldDrawMainBackground = newShouldDrawBG;
244		[self setNeedsDisplay:YES];
245    }
246}
247
248- grid
249{
250	return grid;
251}
252
253- (void)_drawRect:(NSRect)rect
254{
255	[transform concat];
256	[canvas drawRect:[self convertFromViewToCanvasRect:rect] fixBug:NO];
257
258	if ((zoomPercentage / 100.0f) * [grid unitSize].width >= 4 && (zoomPercentage / 100.0f) * [grid unitSize].height >= 4)
259    {
260		[grid drawRect:[self convertFromViewToCanvasRect:[self frame]]];
261    }
262	if (![self shouldTile])
263    {
264		[crosshair drawRect:[self convertFromViewToCanvasRect:[self frame]]];
265    }
266	[transform invert];
267	[transform concat];
268	[transform invert];
269}
270
271- (void)drawRect:(NSRect)rect
272{
273	NSLog(@"rect %",rect);
274
275	[[NSGraphicsContext currentContext] setShouldAntialias:NO];
276	[[NSGraphicsContext currentContext] setImageInterpolation:NSImageInterpolationNone];
277	[[NSColor lightGrayColor] set];
278	NSRectFill(rect);
279	if(canvas == nil || NSEqualSizes([canvas size], NSZeroSize)) { return; }
280	transform = [self setupTransform];
281	[transform concat];
282	if(shouldDrawMainBackground || alternateBackground == nil) { [mainBackground drawRect:rect withinRect:[self visibleRect] withTransform:transform onCanvas:canvas]; }
283	else { [alternateBackground drawRect:rect withinRect:[self visibleRect] withTransform:transform onCanvas:canvas]; }
284	[transform invert];
285	[transform concat];
286	[transform invert];
287	[self _drawRect:rect];
288	if(![self shouldTile]) { return; }
289	[transform translateXBy:-[canvas size].width yBy:0];
290	[self _drawRect:rect];
291	[transform translateXBy:0 yBy:[canvas size].height];
292	[self _drawRect:rect];
293	[transform translateXBy:[canvas size].width yBy:0];
294	[self _drawRect:rect];
295	[transform translateXBy:[canvas size].width yBy:0];
296	[self _drawRect:rect];
297	[transform translateXBy:0 yBy:-[canvas size].height];
298	[self _drawRect:rect];
299	[transform translateXBy:0 yBy:-[canvas size].height];
300	[self _drawRect:rect];
301	[transform translateXBy:-[canvas size].width yBy:0];
302	[self _drawRect:rect];
303	[transform translateXBy:-[canvas size].width yBy:0];
304	[self _drawRect:rect];
305}
306
307- (NSAffineTransform *)setupScaleTransform
308{
309#ifndef __COCOA__
310	zoomPercentage = 600;
311#endif
312	id transformation = [NSAffineTransform transform];
313
314	[transformation scaleBy:zoomPercentage/100.0f];
315	return transformation;
316}
317
318- (NSAffineTransform *)setupTransform
319{
320	id transformation = [self setupScaleTransform];
321
322	if([self shouldTile])
323    {
324		[transformation translateXBy:[canvas size].width yBy:[canvas size].height];
325    }
326	return transformation;
327}
328
329- (BOOL)acceptsFirstResponder
330{
331    return YES;
332}
333
334- (BOOL)isOpaque
335{
336    return YES;
337}
338
339- (void)scrollUpBy:(int)amount
340{
341    [self centerOn:[self convertFromCanvasToViewPoint:NSMakePoint(centeredPoint.x, centeredPoint.y+amount)]];
342}
343
344- (void)scrollRightBy:(int)amount
345{
346    [self centerOn:[self convertFromCanvasToViewPoint:NSMakePoint(centeredPoint.x+amount, centeredPoint.y)]];
347}
348
349- (void)scrollDownBy:(int)amount
350{
351    [self centerOn:[self convertFromCanvasToViewPoint:NSMakePoint(centeredPoint.x, centeredPoint.y-amount)]];
352}
353
354- (void)scrollLeftBy:(int)amount
355{
356    [self centerOn:[self convertFromCanvasToViewPoint:NSMakePoint(centeredPoint.x-amount, centeredPoint.y)]];
357}
358
359- (void)resetCursorRects
360{
361	//    [self addCursorRect:[self visibleRect] cursor:[NSCursor currentCursor]];
362    if(trackingRect != -1) { [self removeTrackingRect:trackingRect]; }
363    trackingRect = [self addTrackingRect:[self visibleRect] owner:self userData:NULL assumeInside:YES];
364}
365
366- (void)mouseEntered:event
367{
368	[self setShouldDrawMainBackground:YES];
369}
370
371- (void)mouseExited:event
372{
373	[self setShouldDrawMainBackground:NO];
374}
375
376- (void)updateCrosshairs:(NSPoint)newLocation
377{
378	if (![crosshair shouldDraw] || [self shouldTile])
379    {
380		return;
381    }
382
383	NSPoint oldPosition = [self convertFromCanvasToViewPoint:[crosshair cursorPosition]];
384	[crosshair setCursorPosition:[self convertFromWindowToCanvasPoint:newLocation]];
385	NSPoint newPosition = [self convertFromCanvasToViewPoint:[crosshair cursorPosition]];
386	NSRect visibleRect = [self visibleRect];
387	NSRect oldXAxis = visibleRect, oldYAxis = visibleRect, newXAxis = visibleRect, newYAxis = visibleRect;
388
389	if (!(oldPosition.y < visibleRect.origin.y || oldPosition.y >= visibleRect.origin.y + visibleRect.size.height)) {
390		oldXAxis.origin.y = oldPosition.y - 1;
391		oldXAxis.size.height = zoomPercentage / 100 + 2;
392		[self displayRect:oldXAxis];
393	}
394	if (!(oldPosition.x < visibleRect.origin.x || oldPosition.x >= visibleRect.origin.x + visibleRect.size.width)) {
395		oldYAxis.origin.x = oldPosition.x - 1;
396		oldYAxis.size.width = zoomPercentage / 100 + 2;
397		[self displayRect:oldYAxis];
398	}
399	if (!(newPosition.y < visibleRect.origin.y || newPosition.y >= visibleRect.origin.y + visibleRect.size.height)) {
400		newXAxis.origin.y = newPosition.y - 1;
401		newXAxis.size.height = zoomPercentage / 100 + 2;
402		[self displayRect:newXAxis];
403	}
404	if (!(newPosition.x < visibleRect.origin.x || newPosition.x >= visibleRect.origin.x + visibleRect.size.width)) {
405		newYAxis.origin.x = newPosition.x - 1;
406		newYAxis.size.width = zoomPercentage / 100 + 2;
407		[self displayRect:newYAxis];
408	}
409}
410
411- (void)updateInfoPanelWithMousePosition:(NSPoint)point dragging:(BOOL)dragging
412{
413	NSPoint cursorPoint = point;
414	cursorPoint.y = [canvas size].height - cursorPoint.y - 1;
415	if (cursorPoint.x < 0) { cursorPoint.x = 0; }
416	if (cursorPoint.y < 0) { cursorPoint.y = 0; }
417	//if (cursorPoint.x > ([canvas size].width - 1)) { cursorPoint.x = [canvas size].width - 1; }
418	//if (cursorPoint.y > ([canvas size].height - 1)) { cursorPoint.y = [canvas size].height - 1; }
419	if (!dragging) {
420		[[PXInfoPanelController sharedInfoPanelController] setDraggingOrigin:cursorPoint];
421	}
422	[[PXInfoPanelController sharedInfoPanelController] setCursorPosition:cursorPoint];
423	[[PXInfoPanelController sharedInfoPanelController] setColorInfo:[[[[PXToolPaletteController sharedToolPaletteController] leftSwitcher] toolWithTag:PXEyedropperToolTag] compositeColorAtPoint:point fromCanvas:canvas]]; // eeew HACK: METHOD SHOULD BE MOVED TO CANVAS
424}
425
426- (void)mouseDown:event
427{
428	NSLog(@"MouseDown");
429	[self updateInfoPanelWithMousePosition:[self convertFromWindowToCanvasPoint:[event locationInWindow]] dragging:NO];
430	NSLog(@"mouseDown to super");
431#ifdef __COCOA__
432	[super mouseDown:event];
433#else
434	NSLog(@" [NSApp keyWindow] title %@",[[NSApp keyWindow] delegate] );
435	[[[NSApp keyWindow] delegate] mouseDown: event];
436#endif
437
438
439
440}
441
442- (void)mouseUp:event
443{
444	[self updateInfoPanelWithMousePosition:[self convertFromWindowToCanvasPoint:[event locationInWindow]] dragging:NO];
445	[super mouseUp:event];
446}
447
448- (void)mouseMoved:event
449{
450	[self updateCrosshairs:[event locationInWindow]];
451	[self updateInfoPanelWithMousePosition:[self convertFromWindowToCanvasPoint:[event locationInWindow]] dragging:NO];
452}
453
454- (void)mouseDragged:event
455{
456	[self updateCrosshairs:[event locationInWindow]];
457	[self updateInfoPanelWithMousePosition:[self convertFromWindowToCanvasPoint:[event locationInWindow]] dragging:YES];
458	[super mouseDragged:event];
459}
460
461- (void)rightMouseDragged:event
462{
463	[self updateCrosshairs:[event locationInWindow]];
464	[self updateInfoPanelWithMousePosition:[self convertFromWindowToCanvasPoint:[event locationInWindow]] dragging:YES];
465	[super rightMouseDragged:event];
466}
467
468@end
469