jens@0: /* This code is based on Apple's "GeekGameBoard" sample code, version 1.0. jens@0: http://developer.apple.com/samplecode/GeekGameBoard/ jens@0: Copyright © 2007 Apple Inc. Copyright © 2008 Jens Alfke. All Rights Reserved. jens@0: jens@0: Redistribution and use in source and binary forms, with or without modification, are permitted jens@0: provided that the following conditions are met: jens@0: jens@0: * Redistributions of source code must retain the above copyright notice, this list of conditions jens@0: and the following disclaimer. jens@0: * Redistributions in binary form must reproduce the above copyright notice, this list of jens@0: conditions and the following disclaimer in the documentation and/or other materials provided jens@0: with the distribution. jens@0: jens@0: THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR jens@0: IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND jens@0: FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRI- jens@0: BUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES jens@0: (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR jens@0: PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN jens@0: CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF jens@0: THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. jens@0: */ jens@0: #import "Card.h" jens@1: #import "GGBTextLayer.h" jens@0: #import "QuartzUtils.h" jens@0: jens@0: jens@0: @implementation Card jens@0: jens@0: jens@4: static CGSize sCardSize = {100,150}; jens@4: jens@0: static CATransform3D kFaceUpTransform, kFaceDownTransform; jens@0: jens@0: + (void) initialize jens@0: { jens@0: if( self==[Card class] ) { jens@0: kFaceUpTransform = kFaceDownTransform = CATransform3DIdentity; jens@0: // Construct a 180-degree rotation matrix: jens@0: kFaceDownTransform.m11 = kFaceDownTransform.m33 = -1; jens@0: // The more obvious way to create kFaceDownTransform would be to call jens@0: // CATransform3DMakeRotation(pi,0,1,0), but due to round-off errors, that transform jens@0: // will have non-zero values in some other places, making it appear to CA as a true jens@0: // 3D transform; this will then cause unexpected clipping behaviors when used. jens@0: } jens@0: } jens@0: jens@0: jens@0: + (NSRange) serialNumberRange; jens@0: { jens@0: NSAssert1(NO,@"%@ forgot to override +serialNumberRange",self); jens@0: return NSMakeRange(0,0); jens@0: } jens@0: jens@0: jens@4: + (CGSize) cardSize {return sCardSize;} jens@4: + (void) setCardSize: (CGSize)size {sCardSize = size;} jens@4: jens@4: jens@0: - (id) initWithSerialNumber: (int)serial position: (CGPoint)pos jens@0: { jens@0: self = [super init]; jens@0: if (self != nil) { jens@0: _serialNumber = serial; jens@4: self.bounds = CGRectMake(0,0,sCardSize.width,sCardSize.height); jens@0: self.position = pos; jens@0: self.edgeAntialiasingMask = 0; jens@0: _back = [self createBack]; jens@0: [self addSublayer: _back]; jens@0: _front = [self createFront]; jens@0: _front.transform = kFaceDownTransform; jens@0: [self addSublayer: _front]; jens@0: } jens@0: return self; jens@0: } jens@0: jens@0: jens@1: - (id) copyWithZone: (NSZone*)zone jens@0: { jens@1: Card *clone = [super copyWithZone: zone]; jens@1: clone->_serialNumber = _serialNumber; jens@1: return clone; jens@0: } jens@0: jens@0: jens@0: - (NSString*) description jens@0: { jens@0: return [NSString stringWithFormat: @"%@[#%i]",self.class,_serialNumber]; jens@0: } jens@0: jens@0: jens@0: @synthesize serialNumber=_serialNumber; jens@0: jens@0: jens@0: - (BOOL) faceUp jens@0: { jens@0: return _faceUp; jens@0: } jens@0: jens@0: - (void) setFaceUp: (BOOL)up jens@0: { jens@0: if( up != _faceUp ) { jens@0: // The Card has separate sub-layers for its front and back. At any time, one of them jens@0: // is hidden, by having a 180 degree rotation about the Y axis. jens@0: // To flip the card, both front and back layers are flipped over. jens@0: CATransform3D xform; jens@0: xform = up ?kFaceUpTransform :kFaceDownTransform; jens@0: _front.transform = xform; jens@0: jens@0: xform = up ?kFaceDownTransform :kFaceUpTransform; jens@0: _back.transform = xform; jens@0: _faceUp = up; jens@0: } jens@0: } jens@0: jens@0: jens@1: - (GGBLayer*) createFront jens@0: { jens@1: GGBLayer *front = [[GGBLayer alloc] init]; jens@4: front.bounds = CGRectMake(0,0,sCardSize.width,sCardSize.height); jens@4: front.position = CGPointMake(sCardSize.width/2,sCardSize.height/2); jens@0: front.edgeAntialiasingMask = 0; jens@0: front.backgroundColor = kWhiteColor; jens@4: front.cornerRadius = 8 * (sCardSize.height/150); jens@0: front.borderWidth = 1; jens@1: front.borderColor = CreateGray(0.7, 1.0); jens@0: front.doubleSided = NO; // this makes the layer invisible when it's flipped jens@0: return [front autorelease]; jens@0: } jens@0: jens@0: jens@1: - (GGBLayer*) createBack jens@0: { jens@0: CGSize size = self.bounds.size; jens@1: GGBLayer *back = [[GGBLayer alloc] init]; jens@0: back.bounds = CGRectMake(0,0,size.width,size.height); jens@4: back.position = CGPointMake(sCardSize.width/2,sCardSize.height/2); jens@8: #if TARGET_OS_IPHONE jens@4: back.backgroundColor = CreateRGB(0.0,0.5,0.5, 1.0); jens@4: #else jens@0: back.contents = (id) GetCGImageNamed(@"/Library/Desktop Pictures/Classic Aqua Blue.jpg"); jens@4: #endif jens@0: back.contentsGravity = kCAGravityResize; jens@0: back.masksToBounds = YES; jens@4: back.borderWidth = 4 * (sCardSize.height/150); jens@0: back.borderColor = kWhiteColor; jens@4: back.cornerRadius = 8 * (sCardSize.height/150); jens@0: back.edgeAntialiasingMask = 0; jens@0: back.doubleSided = NO; // this makes the layer invisible when it's flipped jens@0: jens@8: #if TARGET_OS_IPHONE jens@4: // On iPhone, only Hiragana Kaku includes the coveted snowman glyph... who knows why? jens@4: UIFont *font = [UIFont fontWithName: @"HiraKakuProN-W3" size: 1*size.width]; jens@4: #else jens@4: NSFont *font = [NSFont systemFontOfSize: 1*size.width]; jens@4: #endif jens@1: GGBTextLayer *label = [GGBTextLayer textLayerInSuperlayer: back jens@1: withText: @"\u2603" // Unicode snowman character jens@4: font: font jens@1: alignment: kCALayerWidthSizable|kCALayerHeightSizable]; jens@1: label.foregroundColor = CreateGray(1.0,0.5); jens@0: return [back autorelease]; jens@0: } jens@0: jens@0: jens@0: #pragma mark - jens@0: #pragma mark DRAG-AND-DROP: jens@0: jens@0: jens@8: #if ! TARGET_OS_IPHONE jens@1: jens@0: // An image from another app can be dragged onto a Card to change its background. */ jens@0: jens@0: jens@0: - (NSDragOperation)draggingEntered:(id )sender jens@0: { jens@0: NSPasteboard *pb = [sender draggingPasteboard]; jens@0: if( [NSImage canInitWithPasteboard: pb] ) jens@0: return NSDragOperationCopy; jens@0: else jens@0: return NSDragOperationNone; jens@0: } jens@0: jens@0: - (BOOL)performDragOperation:(id )sender jens@0: { jens@0: CGImageRef image = GetCGImageFromPasteboard([sender draggingPasteboard]); jens@0: if( image ) { jens@1: GGBLayer *face = _faceUp ?_front :_back; jens@0: face.contents = (id) image; jens@0: face.contentsGravity = kCAGravityResizeAspectFill; jens@0: face.masksToBounds = YES; jens@0: return YES; jens@0: } else jens@0: return NO; jens@0: } jens@0: jens@1: #endif jens@0: jens@0: @end