// // MazeView.m // Rat // // Created by Curtis Jones on 2009.11.10. // Copyright 2009 __MyCompanyName__. All rights reserved. // #import "MazeView.h" @interface MazeView (Private) - (void)sizeToFit; - (void)drawSolution:(ratlibpoint_t*)solution inContext:(CGContextRef)context inRect:(NSRect)rect; @end @implementation MazeView @synthesize session = mSession; @synthesize target = mEventCallbackTarget; @synthesize selector = mEventCallbackSelector; #pragma mark - #pragma mark structors /** * * */ - (id)initWithFrame:(NSRect)frame { self = [super initWithFrame:frame]; if (self) { mInTargetMode = FALSE; mIsDirty = FALSE; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(doEventMazeBeginPointSet:) name:@"MazeBeginPointSet" object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(doEventMazeEndPointSet:) name:@"MazeEndPointSet" object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(doEventMazePointAdded:) name:@"MazePointAdded" object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(doEventSolveRoundCompleted:) name:@"SolveRoundCompleted" object:nil]; } return self; } /** * * */ - (void)dealloc { if (mImage != NULL) { CGImageRelease(mImage); mImage = NULL; } [super dealloc]; } #pragma mark - #pragma mark accessors /** * * */ - (CGImageRef)image { return mImage; } /** * * */ - (void)setImage:(CGImageRef)anImage { if (mImage != NULL) { CGImageRelease(mImage); mImage = NULL; } mImage = anImage; CGImageRetain(mImage); [self sizeToFit]; } - (void)sizeToFit { NSLog(@"%s..", __PRETTY_FUNCTION__); if (mImage == nil) return; [self setFrame:CGRectMake(0., 0., CGImageGetWidth(mImage), CGImageGetHeight(mImage))]; [self setBounds:CGRectMake(0., 0., CGImageGetWidth(mImage), CGImageGetHeight(mImage))]; [[self enclosingScrollView] setNeedsDisplay:TRUE]; } #pragma mark - #pragma mark other stuff - (void)setTargetCursor:(BOOL)aBool { if (mInTargetMode != aBool) { mInTargetMode = aBool; [self.window invalidateCursorRectsForView:self]; } } #pragma mark - #pragma mark NSView /** * * */ - (void)drawRect:(NSRect)dirtyRect { if (mImage == nil) return; [self drawRect:dirtyRect inContext:[[NSGraphicsContext currentContext] graphicsPort]]; mIsDirty = FALSE; } /** * * */ - (void)drawRect:(NSRect)dirtyRect inContext:(CGContextRef)context { CGContextDrawImage(context, self.bounds, mImage); [self drawVisitedInContext:context inRect:dirtyRect]; if (mSession->solution != NULL) [self drawSolution:mSession->solution inContext:context inRect:dirtyRect]; // draw the begin marker if it is set if (mSession->begpoint != NULL) [self drawTargetInContext:context point:mSession->begpoint colorR:0 colorG:1 colorB:0 colorA:.5]; // draw the end marker if it is set if (mSession->endpoint != NULL) [self drawTargetInContext:context point:mSession->endpoint colorR:1. colorG:0. colorB:0. colorA:.5]; } /** * * */ - (void)drawSolution:(ratlibpoint_t*)solution inContext:(CGContextRef)context inRect:(NSRect)rect { ratlibpoint_t *point = solution; CGContextSetRGBFillColor(context, 1, 0, 0, 1); do { CGContextFillRect(context, [self rectFromPoint:point width:1 height:1]); } while (NULL != (point = point->prev)); } /** * * */ - (void)drawVisitedInContext:(CGContextRef)context inRect:(NSRect)rect { CGContextSetRGBFillColor(context, 0, 0, 1, 1); ratlibgrid_t *grid = &mSession->grid; ratlibpoint_t *point = ratlib_point(0, 0); uint32_t width=0, height=0; point->x = rect.origin.x; point->y = mSession->image->height - (rect.origin.y + rect.size.height); while (1) { if (ratlibgrid_isvisited(grid, point)) CGContextFillRect(context, [self rectFromPoint:point width:1 height:1]); point->x++; if (++width >= rect.size.width) { point->y++; point->x = rect.origin.x; width = 0; if (++height >= rect.size.height) break; } } ratlibpoint_release(point); } /** * * */ - (void)drawTargetInContext:(CGContextRef)context point:(ratlibpoint_t*)point colorR:(float)r colorG:(float)g colorB:(float)b colorA:(float)a { int32_t x = point->x; int32_t y = mSession->image->height - point->y - 1; CGContextSetRGBFillColor(context, r, g, b, a); CGContextFillRect(context, CGRectMake(x-10, y-2, 21, 5)); CGContextFillRect(context, CGRectMake(x-2, y-10, 5, 21)); } /** * * */ - (NSRect)rectFromPoint:(ratlibpoint_t*)point width:(NSUInteger)width height:(NSUInteger)height { return NSMakeRect(point->x, mSession->image->height-point->y-1, width, height); } /** * Over-ridden to return TRUE so that we can receive mouse events. * */ - (BOOL)acceptsFirstResponder { return TRUE; } /** * * */ - (void)resetCursorRects { if (mInTargetMode) [self addCursorRect:CGRectMake(0., 0., self.frame.size.width, self.frame.size.height) cursor:[NSCursor crosshairCursor]]; else [self removeCursorRect:CGRectMake(0., 0., self.frame.size.width, self.frame.size.height) cursor:[NSCursor crosshairCursor]]; } #pragma mark - #pragma mark NSResponder /** * * */ - (void)mouseDown:(NSEvent *)theEvent { if (mEventCallbackTarget != nil && mEventCallbackSelector != nil) [mEventCallbackTarget performSelector:mEventCallbackSelector withObject:theEvent]; [super mouseDown:theEvent]; } #pragma mark - #pragma mark NSNotificationCenter - (void)doEventSolveRoundCompleted:(NSNotification*)notification { if (mIsDirty) return; mIsDirty = TRUE; [self setNeedsDisplay:TRUE]; } - (void)doEventMazeBeginPointSet:(NSNotification*)notification { if (mIsDirty) return; mIsDirty = TRUE; [self setNeedsDisplay:TRUE]; } - (void)doEventMazeEndPointSet:(NSNotification*)notification { if (mIsDirty) return; mIsDirty = TRUE; [self setNeedsDisplay:TRUE]; } - (void)doEventMazePointAdded:(NSNotification*)notification { if (mIsDirty) return; mIsDirty = TRUE; [self setNeedsDisplay:TRUE]; } @end