/*
IMPORTANT: This Apple software is supplied to you by Apple Computer,
Inc. ("Apple") in consideration of your agreement to the following terms,
and your use, installation, modification or redistribution of this Apple
software constitutes acceptance of these terms. If you do not agree with
these terms, please do not use, install, modify or redistribute this Apple
software.
In consideration of your agreement to abide by the following terms, and
subject to these terms, Apple grants you a personal, non-exclusive
license, under AppleÕs copyrights in this original Apple software (the
"Apple Software"), to use, reproduce, modify and redistribute the Apple
Software, with or without modifications, in source and/or binary forms;
provided that if you redistribute the Apple Software in its entirety and
without modifications, you must retain this notice and the following text
and disclaimers in all such redistributions of the Apple Software.
Neither the name, trademarks, service marks or logos of Apple Computer,
Inc. may be used to endorse or promote products derived from the Apple
Software without specific prior written permission from Apple. Except as
expressly stated in this notice, no other rights or licenses, express or
implied, are granted by Apple herein, including but not limited to any
patent rights that may be infringed by your derivative works or by other
works in which the Apple Software may be incorporated.
The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES
NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE
IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A
PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION
ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION,
MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED AND
WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), STRICT
LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE POSSIBILITY
OF SUCH DAMAGE.
$RCSfile: Board.m,v $
Chess
Copyright (c) 2000-2001 Apple Computer. All rights reserved.
*/
#import <AppKit/NSImage.h>
#import <AppKit/NSPrintInfo.h>
#import <AppKit/NSBitmapImageRep.h>
#import <AppKit/NSWindow.h>
#import <AppKit/NSEvent.h>
#import <AppKit/NSGraphics.h> // NSBeep
#import <Foundation/NSString.h>
#import <Foundation/NSGeometry.h> // NSZeroPoint
#import <Foundation/NSUtilities.h> // MAX, ABS
#import <Foundation/NSException.h>
#include <math.h>
// own interface
#import "Board.h"
// messaging objects
#import "Square.h"
#import "Chess.h" // NSApp
// portability layer
#import "gnuglue.h" // floor_value
// square colors
#define BLACK_SQUARE_COLOR (0.5)
#define WHITE_SQUARE_COLOR (5.0 / 6.0)
// private functions
static NSString *whitePiece( p )
short p;
{
switch( p ) {
case PAWN: return @"white_pawn";
case ROOK: return @"white_rook";
case KNIGHT: return @"white_knight";
case BISHOP: return @"white_bishop";
case KING: return @"white_king";
case QUEEN: return @"white_queen";
default: break;
}
return nil;
}
static NSString *blackPiece( p )
short p;
{
switch( p ) {
case PAWN: return @"black_pawn";
case ROOK: return @"black_rook";
case KNIGHT: return @"black_knight";
case BISHOP: return @"black_bishop";
case KING: return @"black_king";
case QUEEN: return @"black_queen";
default: break;
}
return nil;
}
// Board implementations
@implementation Board
- (id)initWithFrame: (NSRect) f
{
self = [super initWithFrame: f];
if( self ) {
int r, c;
NSSize size;
[self allocateGState];
size.width = f.size.width / 8.0;
size.height = f.size.height / 8.0;
backBitmap = [[NSImage alloc] initWithSize: size];
for( r = 0; r < 8; r++ ) {
for( c = 0; c < 8; c++ ) {
Square *aSquare;
BOOL even;
float bk;
aSquare = [[Square alloc] init];
even = ( ! ((r + c) bk = ( even ) ? BLACK_SQUARE_COLOR : WHITE_SQUARE_COLOR;
[aSquare setBackground: bk];
square[r][c] = aSquare;
}
}
[self setupPieces];
return self;
}
return nil;
}
- (void) setupPieces
{
short *pieces = default_pieces();
short *colors = default_colors();
[self layoutBoard: pieces color: colors];
return;
}
- (void) layoutBoard: (short *)p color: (short *)c
{
int sq;
for( sq = 0; sq < SQUARE_COUNT; sq++ ) {
int row = sq / 8;
int col = sq [self placePiece: p[sq] at: row: col color: c[sq]];
}
return;
}
- (void) placePiece: (short)p at: (int)row : (int)col color: (short)c
{
Square *theSquare = square[row][col];
NSString *piece = ( c == WHITE ) ? whitePiece( p ) : blackPiece( p );
NSImage *image = ( piece ) ? [NSImage imageNamed: piece] : nil;
[theSquare setImage: image];
return;
}
- (void) slidePieceFrom: (int)row1 : (int)col1 to: (int)row2 : (int)col2
{
Square *theSquare;
NSString *icon;
int controlGState;
NSRect pieceRect;
NSPoint backP, endP, winP, roundedBackP;
float incX, incY;
int i, increments;
theSquare = square[row1][col1];
//icon = [[theSquare image] name];
icon = [theSquare imageName];
if( [icon isEqual: @""] )
icon = nil; // ?
if( ! icon )
return;
controlGState = [self gState];
pieceRect.size.width = (float)floor_value( (double)([self frame].size.width / 8.0) );
pieceRect.size.height = (float)floor_value( (double)([self frame].size.height / 8.0) );
backP.x = ( (float)col1 * pieceRect.size.width );
backP.y = ( (float)row1 * pieceRect.size.height );
endP.x = ( (float)col2 * pieceRect.size.width );
endP.y = ( (float)row2 * pieceRect.size.height );
[self lockFocus];
PSgsave();
/* Draw over the piece we are moving. */
pieceRect.origin.x = col1 * pieceRect.size.width;
pieceRect.origin.y = row1 * pieceRect.size.height;
[theSquare drawBackground: pieceRect inView: self];
/* Save background */
[backBitmap lockFocus];
PSgsave();
roundedBackP.x = floor(backP.x);
roundedBackP.y = floor(backP.y);
winP = [[self superview] convertPoint: roundedBackP fromView: self];
PScomposite( winP.x, winP.y, pieceRect.size.width, pieceRect.size.height,
controlGState, (float)0.0, (float)0.0, NSCompositeCopy );
PSgrestore();
[backBitmap unlockFocus];
incX = endP.x - backP.x;
incY = endP.y - backP.y;
increments = (int) MAX( ABS(incX), ABS(incY) ) / 7;
incX = incX / increments;
incY = incY / increments;
for( i = 0; i < increments; i++ ){
/* Restore old background */
[self lockFocus];
[backBitmap compositeToPoint: backP operation: NSCompositeCopy];
[self unlockFocus];
[[self window] flushWindow];
/* Save new background */
backP.x += incX;
backP.y += incY;
[backBitmap lockFocus];
PSgsave();
roundedBackP.x = floor(backP.x);
roundedBackP.y = floor(backP.y);
pieceRect.origin = roundedBackP;
winP = [[self superview] convertPoint: roundedBackP fromView: self];
PScomposite( winP.x, winP.y, pieceRect.size.width,
pieceRect.size.height, controlGState, (float)0.0,
(float)0.0, NSCompositeCopy );
PSgrestore();
[backBitmap unlockFocus];
/* Draw piece at new location. */
[theSquare drawInteriorWithFrame: pieceRect inView: self];
[[self window] flushWindow];
PSsetgray( NSBlack );
PSsetlinewidth( (float)2.0 );
PSclippath();
PSstroke();
[[self window] flushWindow];
}
PSgrestore();
[self unlockFocus];
return;
}
- (int) pieceAt: (int)row : (int)col
{
if( row >= 0 && col >= 0 ) {
Square *theSquare = square[row][col];
return( [theSquare pieceType] );
}
return (int)NO_PIECE;
}
- (void) highlightSquareAt: (int)row : (int)col
{
NSRect cr;
Square *theSquare = square[row][col];
[self lockFocus];
cr.size.width = [self frame].size.width / 8.0;
cr.size.height = [self frame].size.height / 8.0;
cr.origin.x = col * cr.size.width;
cr.origin.y = row * cr.size.height;
[theSquare highlight: cr inView: self];
PSsetgray( NSBlack );
PSsetlinewidth( (float)2.0 );
PSclippath();
PSstroke();
[[self window] flushWindow];
[self unlockFocus];
return;
}
- (void) unhighlightSquareAt: (int)row : (int)col
{
return;
}
- (void) flashSquareAt: (int)row : (int)col
{
return;
}
- (void) print: (id)sender
{
NSPrintInfo *pi = [NSPrintInfo sharedPrintInfo];
NSSize ps = [pi paperSize];
NSSize fs = [self frame].size;
float hm = (ps.width - fs.width) / 2.0;
float vm = (ps.height - fs.height) / 2.0;
[pi setLeftMargin: hm];
[pi setRightMargin: hm];
[pi setTopMargin: vm];
[pi setBottomMargin: vm];
[self lockFocus];
printImage = [[NSBitmapImageRep alloc] initWithFocusedViewRect: [self bounds]];
[self unlockFocus];
[super print: sender];
[printImage release];
printImage = nil;
return;
}
- (void) drawRect: (NSRect)f
{
if( ! printImage ) {
int r, c;
NSRect cr;
PSgsave();
cr.size.width = f.size.width / 8.0;
cr.size.height = f.size.height / 8.0;
for( r = 0; r < 8; r++ ) {
cr.origin.y = r * cr.size.height;
for( c = 0; c < 8; c++ ) {
Square *theSquare = square[r][c];
cr.origin.x = c * cr.size.width;
[theSquare drawWithFrame: cr inView: self];
}
}
PSsetgray( NSBlack );
PSsetlinewidth( (float)2.0 );
PSclippath();
PSstroke();
PSgrestore();
}
else {
[printImage draw];
}
return;
}
- (void) mouseDown: (NSEvent *)event
{
NSException *exception = nil;
if ( [NSApp bothsides] ) {
NSBeep();
}
else if( [NSApp finished] ) {
[NSApp finishedAlert];
[[self window] setAcceptsMouseMovedEvents: YES];
NS_DURING
while( [event type] != NSLeftMouseUp ) {
unsigned int mask = (NSLeftMouseUpMask | NSLeftMouseDraggedMask);
event = [[self window] nextEventMatchingMask: mask];
}
NS_HANDLER
exception = localException;
NS_ENDHANDLER
}
else {
NSPoint pickedP, backP, roundedBackP, winP;
NSRect pieceRect, backR;
int r, c;
Square *theSquare;
int controlGState;
NSString *icon;
NSPoint p;
pickedP = [event locationInWindow];
pickedP = [self convertPoint: pickedP fromView: nil];
backP = pickedP;
//pieceRect.origin = NSZeroPoint;
pieceRect.size.width = [self frame].size.width / 8.0;
pieceRect.size.height = [self frame].size.height / 8.0;
r = floor_value( (double)(pickedP.y / pieceRect.size.height) );
c = floor_value( (double)(pickedP.x / pieceRect.size.width) );
pieceRect.size.width =(float)floor_value((double)pieceRect.size.width);
pieceRect.size.height=(float)floor_value((double)pieceRect.size.height);
backR.origin = NSZeroPoint;
backR.size = pieceRect.size;
pickedP.x = pickedP.x - (((float)c) * pieceRect.size.width);
pickedP.y = pickedP.y - (((float)r) * pieceRect.size.height);
theSquare = square[r][c];
//icon = [[theSquare image] name];
icon = [theSquare imageName];
if( [icon isEqual: @""] )
icon = nil; // ?
if( icon && [self isEnabled] ) {
controlGState = [self gState];
if( ! controlGState ) {
[self allocateGState];
controlGState = [self gState];
}
[self lockFocus];
PSgsave();
/* Draw over the piece we are moving. */
pieceRect.origin.x = c * pieceRect.size.width;
pieceRect.origin.y = r * pieceRect.size.height;
[theSquare drawBackground: pieceRect inView: self];
/* Save background */
[backBitmap lockFocus];
PSgsave();
roundedBackP.x = floor(backP.x);
roundedBackP.y = floor(backP.y);
winP = [[self superview] convertPoint: roundedBackP fromView: self];
PScomposite( winP.x, winP.y, backR.size.width, backR.size.height,
controlGState, (float)0.0, (float)0.0, NSCompositeCopy );
PSgrestore();
[backBitmap unlockFocus];
}
[[self window] setAcceptsMouseMovedEvents: YES];
NS_DURING
while ([event type] != NSLeftMouseUp) {
unsigned int mask = (NSLeftMouseUpMask | NSLeftMouseDraggedMask);
event = [[self window] nextEventMatchingMask: mask];
p = [event locationInWindow];
p = [self convertPoint: p fromView: nil];
if( icon && [self isEnabled] ) {
/* Restore old background */
[self lockFocus];
[backBitmap compositeToPoint:roundedBackP operation:NSCompositeCopy];
[self unlockFocus];
/* Save new background */
backP.x = pieceRect.origin.x = p.x - pickedP.x;
backP.y = pieceRect.origin.y = p.y - pickedP.y;
[backBitmap lockFocus];
PSgsave();
roundedBackP.x = floor(backP.x);
roundedBackP.y = floor(backP.y);
winP = [[self superview] convertPoint: roundedBackP fromView: self];
PScomposite( winP.x, winP.y, backR.size.width,
backR.size.height, controlGState, (float)0.0,
(float)0.0, NSCompositeCopy );
PSgrestore();
[backBitmap unlockFocus];
/* Draw piece at new location. */
[theSquare drawInteriorWithFrame: pieceRect inView: self];
PSsetgray( NSBlack );
PSsetlinewidth( (float)2.0 );
PSclippath();
PSstroke();
[[self window] flushWindow];
}
}
NS_HANDLER
exception = localException;
NS_ENDHANDLER
if( icon && [self isEnabled] ) {
NSSize frame = [self frame].size;
int r2 = floor_value( (double)(p.y / (frame.height / 8.0)) );
int c2 = floor_value( (double)(p.x / (frame.width / 8.0)) );
if( r2 != r || c2 != c ) {
if( ! [NSApp makeMoveFrom: r : c to: r2 : c2] ) {
PSWait();
}
}
[self display];
PSgrestore();
[self unlockFocus];
}
}
if( exception )
[exception raise];
return;
}
@end
// Local Variables:
// tab-width: 8
// End: