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