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@8
|
138 |
#if TARGET_OS_IPHONE
|
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@8
|
151 |
#if TARGET_OS_IPHONE
|
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@8
|
170 |
#if ! TARGET_OS_IPHONE
|
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@11
|
186 |
CGImageRef image = GetCGImageFromPasteboard([sender draggingPasteboard],sender);
|
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
|