* Got it working with latest iPhone SDK.
* Fixed some text alignment issues that showed up on PlayingCards.
* Working on persistence and move-tracking for Game.
5 // Created by Jens Alfke on 3/7/08.
6 // Copyright 2008 __MyCompanyName__. All rights reserved.
10 #import "QuartzUtils.h"
13 @implementation GGBLayer
16 - (NSString*) description
18 return [NSString stringWithFormat: @"%@[(%g,%g)]", self.class,self.position.x,self.position.y];
24 [self setNeedsDisplay];
25 for( CALayer *layer in self.sublayers )
26 if( [layer isKindOfClass: [GGBLayer class]] )
27 ((GGBLayer*)layer).redisplayAll;
29 [layer setNeedsDisplay];
34 - (void)addAnimation:(CAAnimation *)anim forKey:(NSString *)key
36 NSLog(@"%@[%p] addAnimation: %p forKey: %@",[self class],self,anim,key);
37 [super addAnimation: anim forKey: key];
42 - (void) animateAndBlock: (NSString*)keyPath from: (id)from to: (id)to duration: (NSTimeInterval)duration
44 //WARNING: This code works, but is a mess. I hope to find a better way to do this. --Jens 3/16/08
45 CABasicAnimation *anim = [CABasicAnimation animationWithKeyPath: keyPath];
46 anim.duration= duration;
47 anim.fromValue = from;
49 anim.isRemovedOnCompletion = YES;
51 [self addAnimation:anim forKey: @"animateAndBlock:"];
52 _curAnimation = (id)[self animationForKey: @"animateAndBlock:"];
53 [self setValue: to forKeyPath: keyPath]; // animation doesn't update the property value
55 // Now wait for it to finish:
56 while( _curAnimation ) {
57 [[NSRunLoop currentRunLoop] runMode: NSDefaultRunLoopMode//NSEventTrackingRunLoopMode
58 beforeDate: [NSDate dateWithTimeIntervalSinceNow: 0.1]];
62 - (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag
64 if( anim==_curAnimation ) {
73 #pragma mark IPHONE VERSION:
76 - (id) copyWithZone: (NSZone*)zone
78 GGBLayer *clone = [[[self class] alloc] init];
79 clone.bounds = self.bounds;
80 clone.position = self.position;
81 clone.zPosition = self.zPosition;
82 clone.anchorPoint = self.anchorPoint;
83 clone.transform = self.transform;
84 clone.hidden = self.hidden;
85 clone.doubleSided = self.doubleSided;
86 clone.sublayerTransform = self.sublayerTransform;
87 clone.masksToBounds = self.masksToBounds;
88 clone.contents = self.contents; // doesn't copy contents (shallow-copy)
89 clone.contentsRect = self.contentsRect;
90 clone.contentsGravity = self.contentsGravity;
91 clone.minificationFilter = self.minificationFilter;
92 clone.magnificationFilter = self.magnificationFilter;
93 clone.opaque = self.opaque;
94 clone.needsDisplayOnBoundsChange = self.needsDisplayOnBoundsChange;
95 clone.edgeAntialiasingMask = self.edgeAntialiasingMask;
96 clone.backgroundColor = self.backgroundColor;
97 clone.opacity = self.opacity;
98 clone.compositingFilter = self.compositingFilter;
99 clone.filters = self.filters;
100 clone.backgroundFilters = self.backgroundFilters;
101 clone.actions = self.actions;
102 clone.name = self.name;
103 clone.style = self.style;
105 clone.cornerRadius = self.cornerRadius;
106 clone.borderWidth = self.borderWidth;
107 clone.borderColor = self.borderColor;
109 for( GGBLayer *sublayer in self.sublayers ) {
110 sublayer = [sublayer copyWithZone: zone];
111 [clone addSublayer: sublayer];
117 - (CGFloat) cornerRadius {return _cornerRadius;}
118 - (CGFloat) borderWidth {return _borderWidth;}
119 - (CGColorRef) borderColor {return _borderColor;}
121 - (void) setCornerRadius: (CGFloat)r
123 if( r != _cornerRadius ) {
125 [self setNeedsDisplay];
130 - (void) setBorderWidth: (CGFloat)w
132 if( w != _borderWidth ) {
134 self.needsDisplayOnBoundsChange = (_borderWidth>0.0 && _borderColor!=NULL);
135 [self setNeedsDisplay];
140 - (void) setBackgroundColor: (CGColorRef)color
142 if( color != _realBGColor ) {
143 CGColorRelease(_realBGColor);
144 _realBGColor = CGColorRetain(color);
145 [self setNeedsDisplay];
150 - (void) setBorderColor: (CGColorRef)color
152 if( color != _borderColor ) {
153 CGColorRelease(_borderColor);
154 _borderColor = CGColorRetain(color);
155 self.needsDisplayOnBoundsChange = (_borderWidth>0.0 && _borderColor!=NULL);
156 [self setNeedsDisplay];
161 - (void)drawInContext:(CGContextRef)ctx
163 [super drawInContext: ctx];
165 CGContextSaveGState(ctx);
168 CGRect interior = CGRectInset(self.bounds, _borderWidth,_borderWidth);
169 CGContextSetFillColorWithColor(ctx, _realBGColor);
170 if( _cornerRadius <= 0.0 ) {
171 CGContextFillRect(ctx,interior);
173 CGContextBeginPath(ctx);
174 AddRoundRect(ctx,interior,_cornerRadius);
175 CGContextFillPath(ctx);
179 if( _borderWidth > 0.0 && _borderColor!=NULL ) {
180 CGRect border = CGRectInset(self.bounds, _borderWidth/2.0, _borderWidth/2.0);
181 CGContextSetStrokeColorWithColor(ctx, _borderColor);
182 CGContextSetLineWidth(ctx, _borderWidth);
184 if( _cornerRadius <= 0.0 ) {
185 CGContextStrokeRect(ctx,border);
187 CGContextBeginPath(ctx);
188 AddRoundRect(ctx,border,_cornerRadius);
189 CGContextStrokePath(ctx);
193 CGContextRestoreGState(ctx);
200 #pragma mark MAC OS VERSION:
203 - (id) copyWithZone: (NSZone*)zone
205 // NSLayer isn't copyable, but it is archivable. So create a copy by archiving to
206 // a temporary data block, then unarchiving a new layer from that block.
208 // One complication is that, due to a bug in Core Animation, CALayer can't archive
209 // a pattern-based CGColor. So as a workaround, clear the background before archiving,
210 // then restore it afterwards.
212 // Also, archiving a CALayer with an image in it leaks memory. (Filed as rdar://5786865 )
213 // As a workaround, clear the contents before archiving, then restore.
215 CGColorRef bg = CGColorRetain(self.backgroundColor);
216 self.backgroundColor = NULL;
217 id contents = [self.contents retain];
220 NSData *data = [NSKeyedArchiver archivedDataWithRootObject: self];
222 self.backgroundColor = bg;
223 self.contents = contents;
225 GGBLayer *clone = [NSKeyedUnarchiver unarchiveObjectWithData: data];
226 clone.backgroundColor = bg;
227 clone.contents = contents;
231 return [clone retain];