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.
 
     5     Redistribution and use in source and binary forms, with or without modification, are permitted
 
     6     provided that the following conditions are met:
 
     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.
 
    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.
 
    24 #import "GGBTextLayer.h"
 
    25 #import "QuartzUtils.h"
 
    31 static CATransform3D kFaceUpTransform, kFaceDownTransform;
 
    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.
 
    47 + (NSRange) serialNumberRange;
 
    49     NSAssert1(NO,@"%@ forgot to override +serialNumberRange",self);
 
    50     return NSMakeRange(0,0);
 
    54 - (id) initWithSerialNumber: (int)serial position: (CGPoint)pos
 
    58         _serialNumber = serial;
 
    59         self.bounds = CGRectMake(0,0,kCardWidth,kCardHeight);
 
    61         self.edgeAntialiasingMask = 0;
 
    62         _back = [self createBack];
 
    63         [self addSublayer: _back];
 
    64         _front = [self createFront];
 
    65         _front.transform = kFaceDownTransform;
 
    66         [self addSublayer: _front];
 
    72 - (id) copyWithZone: (NSZone*)zone
 
    74     Card *clone = [super copyWithZone: zone];
 
    75     clone->_serialNumber = _serialNumber;
 
    80 - (NSString*) description
 
    82     return [NSString stringWithFormat: @"%@[#%i]",self.class,_serialNumber];
 
    86 @synthesize serialNumber=_serialNumber;
 
    94 - (void) setFaceUp: (BOOL)up
 
    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.
 
   101         xform = up ?kFaceUpTransform :kFaceDownTransform;
 
   102         _front.transform = xform;
 
   104         xform = up ?kFaceDownTransform :kFaceUpTransform;
 
   105         _back.transform = xform;
 
   111 - (GGBLayer*) createFront
 
   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];
 
   126 - (GGBLayer*) createBack
 
   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
 
   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];
 
   151 #pragma mark DRAG-AND-DROP:
 
   154 #if ! TARGET_OS_ASPEN
 
   156 // An image from another app can be dragged onto a Card to change its background. */
 
   159 - (NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender
 
   161     NSPasteboard *pb = [sender draggingPasteboard];
 
   162     if( [NSImage canInitWithPasteboard: pb] )
 
   163         return NSDragOperationCopy;
 
   165         return NSDragOperationNone;
 
   168 - (BOOL)performDragOperation:(id <NSDraggingInfo>)sender
 
   170     CGImageRef image = GetCGImageFromPasteboard([sender draggingPasteboard]);
 
   172         GGBLayer *face = _faceUp ?_front :_back;
 
   173         face.contents = (id) image;
 
   174         face.contentsGravity = kCAGravityResizeAspectFill;
 
   175         face.masksToBounds = YES;