Source/GGBLayer.m
author Jens Alfke <jens@mooseyard.com>
Wed May 28 12:47:10 2008 -0700 (2008-05-28)
changeset 8 45c82a071aca
parent 7 428a194e3e59
child 9 a59acc683080
permissions -rw-r--r--
* 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.
jens@1
     1
//
jens@1
     2
//  GGBLayer.m
jens@1
     3
//  GGB-iPhone
jens@1
     4
//
jens@1
     5
//  Created by Jens Alfke on 3/7/08.
jens@1
     6
//  Copyright 2008 __MyCompanyName__. All rights reserved.
jens@1
     7
//
jens@1
     8
jens@1
     9
#import "GGBLayer.h"
jens@1
    10
#import "QuartzUtils.h"
jens@1
    11
jens@1
    12
jens@1
    13
@implementation GGBLayer
jens@1
    14
jens@1
    15
jens@1
    16
- (NSString*) description
jens@1
    17
{
jens@1
    18
    return [NSString stringWithFormat: @"%@[(%g,%g)]", self.class,self.position.x,self.position.y];
jens@1
    19
}
jens@1
    20
jens@1
    21
jens@4
    22
- (void) redisplayAll
jens@4
    23
{
jens@4
    24
    [self setNeedsDisplay];
jens@4
    25
    for( CALayer *layer in self.sublayers )
jens@4
    26
        if( [layer isKindOfClass: [GGBLayer class]] )
jens@4
    27
            ((GGBLayer*)layer).redisplayAll;
jens@4
    28
        else
jens@4
    29
            [layer setNeedsDisplay];
jens@4
    30
}
jens@4
    31
jens@4
    32
jens@7
    33
/*
jens@7
    34
- (void)addAnimation:(CAAnimation *)anim forKey:(NSString *)key 
jens@7
    35
{
jens@7
    36
    NSLog(@"%@[%p] addAnimation: %p forKey: %@",[self class],self,anim,key);
jens@7
    37
    [super addAnimation: anim forKey: key];
jens@7
    38
}
jens@7
    39
*/
jens@7
    40
jens@7
    41
jens@7
    42
- (void) animateAndBlock: (NSString*)keyPath from: (id)from to: (id)to duration: (NSTimeInterval)duration
jens@7
    43
{
jens@7
    44
    //WARNING: This code works, but is a mess. I hope to find a better way to do this. --Jens 3/16/08
jens@7
    45
    CABasicAnimation *anim = [CABasicAnimation animationWithKeyPath: keyPath];
jens@7
    46
    anim.duration= duration;
jens@7
    47
    anim.fromValue = from;
jens@7
    48
    anim.toValue = to;
jens@7
    49
    anim.isRemovedOnCompletion = YES;
jens@7
    50
    anim.delegate = self;
jens@7
    51
    [self addAnimation:anim forKey: @"animateAndBlock:"];
jens@7
    52
    _curAnimation = (id)[self animationForKey: @"animateAndBlock:"];
jens@7
    53
    [self setValue: to forKeyPath: keyPath];    // animation doesn't update the property value
jens@7
    54
jens@7
    55
    // Now wait for it to finish:
jens@7
    56
    while( _curAnimation ) {
jens@7
    57
        [[NSRunLoop currentRunLoop] runMode: NSDefaultRunLoopMode//NSEventTrackingRunLoopMode
jens@7
    58
                                 beforeDate: [NSDate dateWithTimeIntervalSinceNow: 0.1]];
jens@7
    59
    }
jens@7
    60
}
jens@7
    61
jens@7
    62
- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag
jens@7
    63
{
jens@7
    64
    if( anim==_curAnimation ) {
jens@7
    65
        _curAnimation = nil;
jens@7
    66
    }
jens@7
    67
}
jens@7
    68
jens@7
    69
jens@8
    70
#if TARGET_OS_IPHONE
jens@1
    71
jens@1
    72
#pragma mark -
jens@1
    73
#pragma mark IPHONE VERSION:
jens@1
    74
jens@1
    75
jens@1
    76
- (id) copyWithZone: (NSZone*)zone
jens@1
    77
{
jens@1
    78
    GGBLayer *clone = [[[self class] alloc] init];
jens@1
    79
    clone.bounds = self.bounds;
jens@1
    80
    clone.position = self.position;
jens@1
    81
    clone.zPosition = self.zPosition;
jens@1
    82
    clone.anchorPoint = self.anchorPoint;
jens@1
    83
    clone.transform = self.transform;
jens@1
    84
    clone.hidden = self.hidden;
jens@1
    85
    clone.doubleSided = self.doubleSided;
jens@1
    86
    clone.sublayerTransform = self.sublayerTransform;
jens@1
    87
    clone.masksToBounds = self.masksToBounds;
jens@1
    88
    clone.contents = self.contents;                 // doesn't copy contents (shallow-copy)
jens@1
    89
    clone.contentsRect = self.contentsRect;
jens@1
    90
    clone.contentsGravity = self.contentsGravity;
jens@1
    91
    clone.minificationFilter = self.minificationFilter;
jens@1
    92
    clone.magnificationFilter = self.magnificationFilter;
jens@1
    93
    clone.opaque = self.opaque;
jens@1
    94
    clone.needsDisplayOnBoundsChange = self.needsDisplayOnBoundsChange;
jens@1
    95
    clone.edgeAntialiasingMask = self.edgeAntialiasingMask;
jens@1
    96
    clone.backgroundColor = self.backgroundColor;
jens@1
    97
    clone.opacity = self.opacity;
jens@1
    98
    clone.compositingFilter = self.compositingFilter;
jens@1
    99
    clone.filters = self.filters;
jens@1
   100
    clone.backgroundFilters = self.backgroundFilters;
jens@1
   101
    clone.actions = self.actions;
jens@1
   102
    clone.name = self.name;
jens@1
   103
    clone.style = self.style;
jens@1
   104
    
jens@1
   105
    clone.cornerRadius = self.cornerRadius;
jens@1
   106
    clone.borderWidth = self.borderWidth;
jens@1
   107
    clone.borderColor = self.borderColor;
jens@1
   108
    
jens@1
   109
    for( GGBLayer *sublayer in self.sublayers ) {
jens@1
   110
        sublayer = [sublayer copyWithZone: zone];
jens@1
   111
        [clone addSublayer: sublayer];
jens@1
   112
    }
jens@1
   113
    return clone;
jens@1
   114
}
jens@1
   115
jens@1
   116
jens@1
   117
- (CGFloat) cornerRadius    {return _cornerRadius;}
jens@1
   118
- (CGFloat) borderWidth     {return _borderWidth;}
jens@1
   119
- (CGColorRef) borderColor  {return _borderColor;}
jens@1
   120
jens@1
   121
- (void) setCornerRadius: (CGFloat)r
jens@1
   122
{
jens@1
   123
    if( r != _cornerRadius ) {
jens@1
   124
        _cornerRadius = r;
jens@1
   125
        [self setNeedsDisplay];
jens@1
   126
    }
jens@1
   127
}
jens@1
   128
jens@1
   129
jens@1
   130
- (void) setBorderWidth: (CGFloat)w
jens@1
   131
{
jens@1
   132
    if( w != _borderWidth ) {
jens@1
   133
        _borderWidth = w;
jens@1
   134
        self.needsDisplayOnBoundsChange = (_borderWidth>0.0 && _borderColor!=NULL);
jens@1
   135
        [self setNeedsDisplay];
jens@1
   136
    }
jens@1
   137
}
jens@1
   138
jens@1
   139
jens@1
   140
- (void) setBackgroundColor: (CGColorRef)color
jens@1
   141
{
jens@1
   142
    if( color != _realBGColor ) {
jens@1
   143
        CGColorRelease(_realBGColor);
jens@1
   144
        _realBGColor = CGColorRetain(color);
jens@1
   145
        [self setNeedsDisplay];
jens@1
   146
    }
jens@1
   147
}
jens@1
   148
jens@1
   149
jens@1
   150
- (void) setBorderColor: (CGColorRef)color
jens@1
   151
{
jens@1
   152
    if( color != _borderColor ) {
jens@1
   153
        CGColorRelease(_borderColor);
jens@1
   154
        _borderColor = CGColorRetain(color);
jens@1
   155
        self.needsDisplayOnBoundsChange = (_borderWidth>0.0 && _borderColor!=NULL);
jens@1
   156
        [self setNeedsDisplay];
jens@1
   157
    }
jens@1
   158
}
jens@1
   159
jens@1
   160
jens@1
   161
- (void)drawInContext:(CGContextRef)ctx
jens@1
   162
{
jens@4
   163
    [super drawInContext: ctx];
jens@4
   164
    
jens@1
   165
    CGContextSaveGState(ctx);
jens@1
   166
jens@1
   167
    if( _realBGColor ) {
jens@1
   168
        CGRect interior = CGRectInset(self.bounds, _borderWidth,_borderWidth);
jens@1
   169
        CGContextSetFillColorWithColor(ctx, _realBGColor);
jens@1
   170
        if( _cornerRadius <= 0.0 ) {
jens@1
   171
            CGContextFillRect(ctx,interior);
jens@1
   172
        } else {
jens@1
   173
            CGContextBeginPath(ctx);
jens@1
   174
            AddRoundRect(ctx,interior,_cornerRadius);
jens@1
   175
            CGContextFillPath(ctx);
jens@1
   176
        }
jens@1
   177
    }
jens@1
   178
    
jens@1
   179
    if( _borderWidth > 0.0 && _borderColor!=NULL ) {
jens@1
   180
        CGRect border = CGRectInset(self.bounds, _borderWidth/2.0, _borderWidth/2.0);
jens@1
   181
        CGContextSetStrokeColorWithColor(ctx, _borderColor);
jens@1
   182
        CGContextSetLineWidth(ctx, _borderWidth);
jens@1
   183
        
jens@1
   184
        if( _cornerRadius <= 0.0 ) {
jens@1
   185
            CGContextStrokeRect(ctx,border);
jens@1
   186
        } else {
jens@1
   187
            CGContextBeginPath(ctx);
jens@1
   188
            AddRoundRect(ctx,border,_cornerRadius);
jens@1
   189
            CGContextStrokePath(ctx);
jens@1
   190
        }
jens@1
   191
    }
jens@1
   192
    
jens@1
   193
    CGContextRestoreGState(ctx);
jens@1
   194
}
jens@1
   195
jens@1
   196
jens@1
   197
#else
jens@1
   198
jens@1
   199
#pragma mark -
jens@1
   200
#pragma mark MAC OS VERSION:
jens@1
   201
jens@1
   202
jens@1
   203
- (id) copyWithZone: (NSZone*)zone
jens@1
   204
{
jens@1
   205
    // NSLayer isn't copyable, but it is archivable. So create a copy by archiving to
jens@1
   206
    // a temporary data block, then unarchiving a new layer from that block.
jens@1
   207
    
jens@1
   208
    // One complication is that, due to a bug in Core Animation, CALayer can't archive
jens@1
   209
    // a pattern-based CGColor. So as a workaround, clear the background before archiving,
jens@1
   210
    // then restore it afterwards.
jens@1
   211
    
jens@1
   212
    // Also, archiving a CALayer with an image in it leaks memory. (Filed as rdar://5786865 )
jens@1
   213
    // As a workaround, clear the contents before archiving, then restore.
jens@1
   214
    
jens@1
   215
    CGColorRef bg = CGColorRetain(self.backgroundColor);
jens@1
   216
    self.backgroundColor = NULL;
jens@1
   217
    id contents = [self.contents retain];
jens@1
   218
    self.contents = nil;
jens@1
   219
    
jens@1
   220
    NSData *data = [NSKeyedArchiver archivedDataWithRootObject: self];
jens@1
   221
    
jens@1
   222
    self.backgroundColor = bg;
jens@1
   223
    self.contents = contents;
jens@1
   224
jens@1
   225
    GGBLayer *clone = [NSKeyedUnarchiver unarchiveObjectWithData: data];
jens@1
   226
    clone.backgroundColor = bg;
jens@1
   227
    clone.contents = contents;
jens@1
   228
    CGColorRelease(bg);
jens@1
   229
    [contents release];
jens@1
   230
jens@1
   231
    return [clone retain];
jens@1
   232
}
jens@1
   233
jens@1
   234
jens@1
   235
#endif
jens@1
   236
jens@1
   237
jens@1
   238
@end