Source/Card.m
author Jens Alfke <jens@mooseyard.com>
Sun Mar 16 15:06:47 2008 -0700 (2008-03-16)
changeset 7 428a194e3e59
parent 1 3eb7be1dd7b6
child 8 45c82a071aca
permissions -rw-r--r--
Game class now tracks board state and moves, as strings, and can step through its history.
Fixed another bug in Go (you could drag your captured stones back to the board!)
jens@0
     1
/*  This code is based on Apple's "GeekGameBoard" sample code, version 1.0.
jens@0
     2
    http://developer.apple.com/samplecode/GeekGameBoard/
jens@0
     3
    Copyright © 2007 Apple Inc. Copyright © 2008 Jens Alfke. All Rights Reserved.
jens@0
     4
jens@0
     5
    Redistribution and use in source and binary forms, with or without modification, are permitted
jens@0
     6
    provided that the following conditions are met:
jens@0
     7
jens@0
     8
    * Redistributions of source code must retain the above copyright notice, this list of conditions
jens@0
     9
      and the following disclaimer.
jens@0
    10
    * Redistributions in binary form must reproduce the above copyright notice, this list of
jens@0
    11
      conditions and the following disclaimer in the documentation and/or other materials provided
jens@0
    12
      with the distribution.
jens@0
    13
jens@0
    14
    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
jens@0
    15
    IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 
jens@0
    16
    FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRI-
jens@0
    17
    BUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
jens@0
    18
    (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
jens@0
    19
    PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
jens@0
    20
    CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 
jens@0
    21
    THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
jens@0
    22
*/
jens@0
    23
#import "Card.h"
jens@1
    24
#import "GGBTextLayer.h"
jens@0
    25
#import "QuartzUtils.h"
jens@0
    26
jens@0
    27
jens@0
    28
@implementation Card
jens@0
    29
jens@0
    30
jens@4
    31
static CGSize sCardSize = {100,150};
jens@4
    32
jens@0
    33
static CATransform3D kFaceUpTransform, kFaceDownTransform;
jens@0
    34
jens@0
    35
+ (void) initialize
jens@0
    36
{
jens@0
    37
    if( self==[Card class] ) {
jens@0
    38
        kFaceUpTransform = kFaceDownTransform = CATransform3DIdentity;
jens@0
    39
        // Construct a 180-degree rotation matrix:
jens@0
    40
        kFaceDownTransform.m11 = kFaceDownTransform.m33 = -1;
jens@0
    41
        // The more obvious way to create kFaceDownTransform would be to call
jens@0
    42
        // CATransform3DMakeRotation(pi,0,1,0), but due to round-off errors, that transform
jens@0
    43
        // will have non-zero values in some other places, making it appear to CA as a true
jens@0
    44
        // 3D transform; this will then cause unexpected clipping behaviors when used.
jens@0
    45
    }
jens@0
    46
}
jens@0
    47
jens@0
    48
jens@0
    49
+ (NSRange) serialNumberRange;
jens@0
    50
{
jens@0
    51
    NSAssert1(NO,@"%@ forgot to override +serialNumberRange",self);
jens@0
    52
    return NSMakeRange(0,0);
jens@0
    53
}
jens@0
    54
jens@0
    55
jens@4
    56
+ (CGSize) cardSize                 {return sCardSize;}
jens@4
    57
+ (void) setCardSize: (CGSize)size  {sCardSize = size;}
jens@4
    58
jens@4
    59
jens@0
    60
- (id) initWithSerialNumber: (int)serial position: (CGPoint)pos
jens@0
    61
{
jens@0
    62
    self = [super init];
jens@0
    63
    if (self != nil) {
jens@0
    64
        _serialNumber = serial;
jens@4
    65
        self.bounds = CGRectMake(0,0,sCardSize.width,sCardSize.height);
jens@0
    66
        self.position = pos;
jens@0
    67
        self.edgeAntialiasingMask = 0;
jens@0
    68
        _back = [self createBack];
jens@0
    69
        [self addSublayer: _back];
jens@0
    70
        _front = [self createFront];
jens@0
    71
        _front.transform = kFaceDownTransform;
jens@0
    72
        [self addSublayer: _front];
jens@0
    73
    }
jens@0
    74
    return self;
jens@0
    75
}
jens@0
    76
jens@0
    77
jens@1
    78
- (id) copyWithZone: (NSZone*)zone
jens@0
    79
{
jens@1
    80
    Card *clone = [super copyWithZone: zone];
jens@1
    81
    clone->_serialNumber = _serialNumber;
jens@1
    82
    return clone;
jens@0
    83
}
jens@0
    84
jens@0
    85
jens@0
    86
- (NSString*) description
jens@0
    87
{
jens@0
    88
    return [NSString stringWithFormat: @"%@[#%i]",self.class,_serialNumber];
jens@0
    89
}
jens@0
    90
jens@0
    91
jens@0
    92
@synthesize serialNumber=_serialNumber;
jens@0
    93
jens@0
    94
jens@0
    95
- (BOOL) faceUp
jens@0
    96
{
jens@0
    97
    return _faceUp;
jens@0
    98
}
jens@0
    99
jens@0
   100
- (void) setFaceUp: (BOOL)up
jens@0
   101
{
jens@0
   102
    if( up != _faceUp ) {
jens@0
   103
        // The Card has separate sub-layers for its front and back. At any time, one of them
jens@0
   104
        // is hidden, by having a 180 degree rotation about the Y axis.
jens@0
   105
        // To flip the card, both front and back layers are flipped over.
jens@0
   106
        CATransform3D xform;
jens@0
   107
        xform = up ?kFaceUpTransform :kFaceDownTransform;
jens@0
   108
        _front.transform = xform;
jens@0
   109
        
jens@0
   110
        xform = up ?kFaceDownTransform :kFaceUpTransform;
jens@0
   111
        _back.transform = xform;
jens@0
   112
        _faceUp = up;
jens@0
   113
    }
jens@0
   114
}
jens@0
   115
jens@0
   116
jens@1
   117
- (GGBLayer*) createFront
jens@0
   118
{
jens@1
   119
    GGBLayer *front = [[GGBLayer alloc] init];
jens@4
   120
    front.bounds = CGRectMake(0,0,sCardSize.width,sCardSize.height);
jens@4
   121
    front.position = CGPointMake(sCardSize.width/2,sCardSize.height/2);
jens@0
   122
    front.edgeAntialiasingMask = 0;
jens@0
   123
    front.backgroundColor = kWhiteColor;
jens@4
   124
    front.cornerRadius = 8 * (sCardSize.height/150);
jens@0
   125
    front.borderWidth = 1;
jens@1
   126
    front.borderColor = CreateGray(0.7, 1.0);
jens@0
   127
    front.doubleSided = NO;         // this makes the layer invisible when it's flipped
jens@0
   128
    return [front autorelease];
jens@0
   129
}
jens@0
   130
jens@0
   131
jens@1
   132
- (GGBLayer*) createBack
jens@0
   133
{
jens@0
   134
    CGSize size = self.bounds.size;
jens@1
   135
    GGBLayer *back = [[GGBLayer alloc] init];
jens@0
   136
    back.bounds = CGRectMake(0,0,size.width,size.height);
jens@4
   137
    back.position = CGPointMake(sCardSize.width/2,sCardSize.height/2);
jens@4
   138
#if TARGET_OS_ASPEN
jens@4
   139
    back.backgroundColor = CreateRGB(0.0,0.5,0.5, 1.0);
jens@4
   140
#else
jens@0
   141
    back.contents = (id) GetCGImageNamed(@"/Library/Desktop Pictures/Classic Aqua Blue.jpg");
jens@4
   142
#endif
jens@0
   143
    back.contentsGravity = kCAGravityResize;
jens@0
   144
    back.masksToBounds = YES;
jens@4
   145
    back.borderWidth = 4 * (sCardSize.height/150);
jens@0
   146
    back.borderColor = kWhiteColor;
jens@4
   147
    back.cornerRadius = 8 * (sCardSize.height/150);
jens@0
   148
    back.edgeAntialiasingMask = 0;
jens@0
   149
    back.doubleSided = NO;          // this makes the layer invisible when it's flipped
jens@0
   150
    
jens@4
   151
#if TARGET_OS_ASPEN
jens@4
   152
    // On iPhone, only Hiragana Kaku includes the coveted snowman glyph... who knows why?
jens@4
   153
    UIFont *font = [UIFont fontWithName: @"HiraKakuProN-W3" size: 1*size.width];
jens@4
   154
#else
jens@4
   155
    NSFont *font = [NSFont systemFontOfSize: 1*size.width];
jens@4
   156
#endif
jens@1
   157
    GGBTextLayer *label = [GGBTextLayer textLayerInSuperlayer: back
jens@1
   158
                                                     withText: @"\u2603"          // Unicode snowman character
jens@4
   159
                                                         font: font
jens@1
   160
                                                    alignment: kCALayerWidthSizable|kCALayerHeightSizable];
jens@1
   161
    label.foregroundColor = CreateGray(1.0,0.5);
jens@0
   162
    return [back autorelease];
jens@0
   163
}    
jens@0
   164
jens@0
   165
jens@0
   166
#pragma mark -
jens@0
   167
#pragma mark DRAG-AND-DROP:
jens@0
   168
jens@0
   169
jens@1
   170
#if ! TARGET_OS_ASPEN
jens@1
   171
jens@0
   172
// An image from another app can be dragged onto a Card to change its background. */
jens@0
   173
jens@0
   174
jens@0
   175
- (NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender
jens@0
   176
{
jens@0
   177
    NSPasteboard *pb = [sender draggingPasteboard];
jens@0
   178
    if( [NSImage canInitWithPasteboard: pb] )
jens@0
   179
        return NSDragOperationCopy;
jens@0
   180
    else
jens@0
   181
        return NSDragOperationNone;
jens@0
   182
}
jens@0
   183
jens@0
   184
- (BOOL)performDragOperation:(id <NSDraggingInfo>)sender
jens@0
   185
{
jens@0
   186
    CGImageRef image = GetCGImageFromPasteboard([sender draggingPasteboard]);
jens@0
   187
    if( image ) {
jens@1
   188
        GGBLayer *face = _faceUp ?_front :_back;
jens@0
   189
        face.contents = (id) image;
jens@0
   190
        face.contentsGravity = kCAGravityResizeAspectFill;
jens@0
   191
        face.masksToBounds = YES;
jens@0
   192
        return YES;
jens@0
   193
    } else
jens@0
   194
        return NO;
jens@0
   195
}
jens@0
   196
jens@1
   197
#endif
jens@0
   198
jens@0
   199
@end