TicTacToe/AAPLTicTacToeBoardView.m
/* |
Copyright (C) 2016 Apple Inc. All Rights Reserved. |
See LICENSE.txt for this sample’s licensing information |
Abstract: |
An example demonstrating adding accessibility to an NSView subclass that behaves like a group by implementing the NSAccessibilityGroup protocol |
and using NSAccessibilityElement to represent each of the items the view draws. |
*/ |
#import "AAPLTicTacToeBoardView.h" |
#import "AAPLTicTacToeSquareAccessibilityElement.h" |
@implementation AAPLTicTacToeBoardView |
@synthesize accessibilityChildren = _accessibilityChildren; |
- (NSRect)squareRectforRow:(NSUInteger)row column:(NSUInteger)column |
{ |
AAPLTicTacToeBoard *board = self.game.board; |
NSRect bounds = self.bounds; |
CGFloat height = bounds.size.height; |
CGFloat squareWidth = bounds.size.width / board.numColumns; |
CGFloat squareHeight = height / board.numRows; |
CGFloat inset = squareWidth / 5.0; |
NSRect squareRect = NSZeroRect; |
if ( row < board.numRows && column < board.numColumns ) |
{ |
squareRect = NSMakeRect(column * squareWidth + inset, |
height - (row + 1) * squareHeight + inset, |
squareWidth - 2 * inset, |
squareHeight - 2 * inset); |
} |
return squareRect; |
} |
#pragma mark - Mouse Event Handling |
- (void)mouseUp:(NSEvent *)mouseEvent |
{ |
NSPoint localPoint = [self convertPoint:mouseEvent.locationInWindow fromView:nil]; |
CGFloat row = floor((self.bounds.size.height - localPoint.y) / (self.bounds.size.height / 3.0)); |
CGFloat column = floor(localPoint.x / (self.bounds.size.width / 3.0)); |
[self.delegate playSquareAtRow:row column:column]; |
[self setNeedsDisplay:YES]; |
} |
#pragma mark - Drawing |
- (void)drawRect:(NSRect)dirtyRect |
{ |
[super drawRect:dirtyRect]; |
[self drawGrid]; |
[self drawSquares]; |
[self drawWinLine]; |
} |
- (void)drawGrid |
{ |
NSRect bounds = self.bounds; |
CGFloat width = bounds.size.width; |
CGFloat height = bounds.size.height; |
[[NSColor blackColor] set]; |
[NSBezierPath setDefaultLineWidth:1.0]; |
[NSBezierPath strokeLineFromPoint:NSMakePoint(width / 3.0, 0.0) toPoint:NSMakePoint(width / 3.0, height)]; |
[NSBezierPath strokeLineFromPoint:NSMakePoint(2.0 * width / 3.0, 0.0) toPoint:NSMakePoint(2.0 * width / 3.0, height)]; |
[NSBezierPath strokeLineFromPoint:NSMakePoint(0.0, height / 3.0) toPoint:NSMakePoint(width, height/ 3.0)]; |
[NSBezierPath strokeLineFromPoint:NSMakePoint(0.0, 2.0 * height / 3.0 ) toPoint:NSMakePoint(width, 2.0 * height / 3.0)]; |
} |
- (void)drawSquares |
{ |
[NSBezierPath setDefaultLineWidth:3.0]; |
AAPLTicTacToeGame *game = self.game; |
AAPLTicTacToeBoard *board = game.board; |
AAPLTicTacToeSquare *square; |
NSUInteger numRows = board.numRows; |
NSUInteger numColumns = board.numColumns; |
for ( NSUInteger row = 0; row < numRows; row++ ) |
{ |
for ( NSUInteger column = 0; column < numColumns; column++ ) |
{ |
square = [board squareAtRow:row column:column]; |
if ( square.isX ) |
{ |
[self drawXAtRow:row column:column]; |
} |
else if ( square.isO ) |
{ |
[self drawOAtRow:row column:column]; |
} |
} |
} |
} |
- (void)drawXAtRow:(NSUInteger)row column:(NSUInteger)column |
{ |
NSRect squareRect = [self squareRectforRow:row column:column]; |
NSPoint topLeft = NSMakePoint(NSMinX(squareRect), NSMaxY(squareRect)); |
NSPoint topRight = NSMakePoint(NSMaxX(squareRect), NSMaxY(squareRect)); |
NSPoint bottomLeft = NSMakePoint(NSMinX(squareRect), NSMinY(squareRect)); |
NSPoint bottomRight = NSMakePoint(NSMaxX(squareRect), NSMinY(squareRect)); |
[NSBezierPath strokeLineFromPoint:topLeft toPoint:bottomRight]; |
[NSBezierPath strokeLineFromPoint:topRight toPoint:bottomLeft]; |
} |
- (void)drawOAtRow:(NSUInteger)row column:(NSUInteger)column |
{ |
NSRect squareRect = [self squareRectforRow:row column:column]; |
NSPoint center = NSMakePoint(NSMidX(squareRect), NSMidY(squareRect)); |
NSBezierPath *circlePath = [[NSBezierPath alloc] init]; |
[circlePath appendBezierPathWithArcWithCenter:center radius:squareRect.size.height / 2.0 startAngle:0 endAngle:360.0]; |
[circlePath stroke]; |
} |
- (void)drawWinLine |
{ |
AAPLTicTacToeGame *game = self.game; |
NSUInteger height = self.bounds.size.height; |
NSUInteger width = self.bounds.size.width; |
switch ( game.winType ) |
{ |
case AAPLTicTacToeGameWinTypeRow: |
[NSBezierPath setDefaultLineWidth:4]; |
[[NSColor redColor] set]; |
[NSBezierPath strokeLineFromPoint:NSMakePoint(0.0, height - (2 * game.winningRow + 1) * (height / 6.0)) |
toPoint:NSMakePoint(width, height - (2 * game.winningRow + 1) * (height / 6.0))]; |
break; |
case AAPLTicTacToeGameWinTypeColumn: |
[NSBezierPath setDefaultLineWidth:4]; |
[[NSColor redColor] set]; |
[NSBezierPath strokeLineFromPoint:NSMakePoint((2 * game.winningColumn + 1) * (width / 6.0), 0.0) |
toPoint:NSMakePoint((2 * game.winningColumn + 1) * (width / 6.0), height)]; |
break; |
case AAPLTicTacToeGameWinTypeTopLeftDiagonal: |
[NSBezierPath setDefaultLineWidth:4]; |
[[NSColor redColor] set]; |
[NSBezierPath strokeLineFromPoint:NSMakePoint(0.0, height) |
toPoint:NSMakePoint(width, 0.0)]; |
break; |
case AAPLTicTacToeGameWinTypeTopRightDiagonal: |
[NSBezierPath setDefaultLineWidth:4]; |
[[NSColor redColor] set]; |
[NSBezierPath strokeLineFromPoint:NSMakePoint(0.0, 0.0) |
toPoint:NSMakePoint(width, height)]; |
break; |
default: |
break; |
} |
} |
#pragma mark - Accessibility |
- (NSString *)accessibilityLabel |
{ |
return NSLocalizedString(@"tic tac toe board", nil); |
} |
// This view draws all of its elements (the tic tac toe squares) itself. |
// NSAccessibilityElement is used to make these squares individually available to accessibility clients |
// by returning an element for each square from -(NSArray *)accessibilityChildren |
- (NSArray *)accessibilityChildren |
{ |
// if the children haven't been created yet |
if ( _accessibilityChildren == nil ) |
{ |
// make an array to hold them |
NSMutableArray *accessibilityChildren = [NSMutableArray new]; |
AAPLTicTacToeBoard *board = self.game.board; |
AAPLTicTacToeSquareAccessibilityElement *squareAccessibilityElement; |
// for each square of the board |
for ( NSUInteger row = 0; row < board.numRows; row++ ) |
{ |
for ( NSUInteger column = 0; column < board.numColumns; column++ ) |
{ |
// create an accessibility element for the square |
squareAccessibilityElement = [[AAPLTicTacToeSquareAccessibilityElement alloc] initWithRow:row |
column:column |
delegate:self.delegate]; |
// set the parent and frame |
squareAccessibilityElement.accessibilityParent = self; |
squareAccessibilityElement.accessibilityFrameInParentSpace = [self squareRectforRow:row column:column]; |
// and add it to the array |
[accessibilityChildren addObject:squareAccessibilityElement]; |
} |
} |
// hold onto the accessibility elements the entire time they are shown in the UI |
_accessibilityChildren = accessibilityChildren; |
} |
return _accessibilityChildren; |
} |
#pragma mark - Support IB_DESIGNABLE |
// Executed when your view is being prepared for display in Interface Builder. |
- (void)prepareForInterfaceBuilder |
{ |
// Add visual interest in Interface Builder by instantiating a game and playing two moves. |
self.game = [AAPLTicTacToeGame new]; |
[self.game playSquareAtRow:0 column:0]; |
[self.game playSquareAtRow:1 column:1]; |
} |
@end |
Copyright © 2016 Apple Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2016-02-18