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