| 
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@1
 | 
    22  | 
#if TARGET_OS_ASPEN
  | 
| 
jens@1
 | 
    23  | 
  | 
| 
jens@1
 | 
    24  | 
#pragma mark -
  | 
| 
jens@1
 | 
    25  | 
#pragma mark IPHONE VERSION:
  | 
| 
jens@1
 | 
    26  | 
  | 
| 
jens@1
 | 
    27  | 
  | 
| 
jens@1
 | 
    28  | 
- (id) copyWithZone: (NSZone*)zone
  | 
| 
jens@1
 | 
    29  | 
{
 | 
| 
jens@1
 | 
    30  | 
    GGBLayer *clone = [[[self class] alloc] init];
  | 
| 
jens@1
 | 
    31  | 
    clone.bounds = self.bounds;
  | 
| 
jens@1
 | 
    32  | 
    clone.position = self.position;
  | 
| 
jens@1
 | 
    33  | 
    clone.zPosition = self.zPosition;
  | 
| 
jens@1
 | 
    34  | 
    clone.anchorPoint = self.anchorPoint;
  | 
| 
jens@1
 | 
    35  | 
    clone.transform = self.transform;
  | 
| 
jens@1
 | 
    36  | 
    clone.hidden = self.hidden;
  | 
| 
jens@1
 | 
    37  | 
    clone.doubleSided = self.doubleSided;
  | 
| 
jens@1
 | 
    38  | 
    clone.sublayerTransform = self.sublayerTransform;
  | 
| 
jens@1
 | 
    39  | 
    clone.masksToBounds = self.masksToBounds;
  | 
| 
jens@1
 | 
    40  | 
    clone.contents = self.contents;                 // doesn't copy contents (shallow-copy)
  | 
| 
jens@1
 | 
    41  | 
    clone.contentsRect = self.contentsRect;
  | 
| 
jens@1
 | 
    42  | 
    clone.contentsGravity = self.contentsGravity;
  | 
| 
jens@1
 | 
    43  | 
    clone.minificationFilter = self.minificationFilter;
  | 
| 
jens@1
 | 
    44  | 
    clone.magnificationFilter = self.magnificationFilter;
  | 
| 
jens@1
 | 
    45  | 
    clone.opaque = self.opaque;
  | 
| 
jens@1
 | 
    46  | 
    clone.needsDisplayOnBoundsChange = self.needsDisplayOnBoundsChange;
  | 
| 
jens@1
 | 
    47  | 
    clone.edgeAntialiasingMask = self.edgeAntialiasingMask;
  | 
| 
jens@1
 | 
    48  | 
    clone.backgroundColor = self.backgroundColor;
  | 
| 
jens@1
 | 
    49  | 
    clone.opacity = self.opacity;
  | 
| 
jens@1
 | 
    50  | 
    clone.compositingFilter = self.compositingFilter;
  | 
| 
jens@1
 | 
    51  | 
    clone.filters = self.filters;
  | 
| 
jens@1
 | 
    52  | 
    clone.backgroundFilters = self.backgroundFilters;
  | 
| 
jens@1
 | 
    53  | 
    clone.actions = self.actions;
  | 
| 
jens@1
 | 
    54  | 
    clone.name = self.name;
  | 
| 
jens@1
 | 
    55  | 
    clone.style = self.style;
  | 
| 
jens@1
 | 
    56  | 
    
  | 
| 
jens@1
 | 
    57  | 
    clone.cornerRadius = self.cornerRadius;
  | 
| 
jens@1
 | 
    58  | 
    clone.borderWidth = self.borderWidth;
  | 
| 
jens@1
 | 
    59  | 
    clone.borderColor = self.borderColor;
  | 
| 
jens@1
 | 
    60  | 
    clone.autoresizingMask = self.autoresizingMask;
  | 
| 
jens@1
 | 
    61  | 
    
  | 
| 
jens@1
 | 
    62  | 
    for( GGBLayer *sublayer in self.sublayers ) {
 | 
| 
jens@1
 | 
    63  | 
        sublayer = [sublayer copyWithZone: zone];
  | 
| 
jens@1
 | 
    64  | 
        [clone addSublayer: sublayer];
  | 
| 
jens@1
 | 
    65  | 
    }
  | 
| 
jens@1
 | 
    66  | 
    return clone;
  | 
| 
jens@1
 | 
    67  | 
}
  | 
| 
jens@1
 | 
    68  | 
  | 
| 
jens@1
 | 
    69  | 
  | 
| 
jens@1
 | 
    70  | 
@synthesize autoresizingMask=_autoresizingMask;
  | 
| 
jens@1
 | 
    71  | 
  | 
| 
jens@1
 | 
    72  | 
- (CGFloat) cornerRadius    {return _cornerRadius;}
 | 
| 
jens@1
 | 
    73  | 
- (CGFloat) borderWidth     {return _borderWidth;}
 | 
| 
jens@1
 | 
    74  | 
- (CGColorRef) borderColor  {return _borderColor;}
 | 
| 
jens@1
 | 
    75  | 
  | 
| 
jens@1
 | 
    76  | 
- (void) setCornerRadius: (CGFloat)r
  | 
| 
jens@1
 | 
    77  | 
{
 | 
| 
jens@1
 | 
    78  | 
    if( r != _cornerRadius ) {
 | 
| 
jens@1
 | 
    79  | 
        _cornerRadius = r;
  | 
| 
jens@1
 | 
    80  | 
        [self setNeedsDisplay];
  | 
| 
jens@1
 | 
    81  | 
    }
  | 
| 
jens@1
 | 
    82  | 
}
  | 
| 
jens@1
 | 
    83  | 
  | 
| 
jens@1
 | 
    84  | 
  | 
| 
jens@1
 | 
    85  | 
- (void) setBorderWidth: (CGFloat)w
  | 
| 
jens@1
 | 
    86  | 
{
 | 
| 
jens@1
 | 
    87  | 
    if( w != _borderWidth ) {
 | 
| 
jens@1
 | 
    88  | 
        _borderWidth = w;
  | 
| 
jens@1
 | 
    89  | 
        self.needsDisplayOnBoundsChange = (_borderWidth>0.0 && _borderColor!=NULL);
  | 
| 
jens@1
 | 
    90  | 
        [self setNeedsDisplay];
  | 
| 
jens@1
 | 
    91  | 
    }
  | 
| 
jens@1
 | 
    92  | 
}
  | 
| 
jens@1
 | 
    93  | 
  | 
| 
jens@1
 | 
    94  | 
  | 
| 
jens@1
 | 
    95  | 
- (void) setBackgroundColor: (CGColorRef)color
  | 
| 
jens@1
 | 
    96  | 
{
 | 
| 
jens@1
 | 
    97  | 
    if( color != _realBGColor ) {
 | 
| 
jens@1
 | 
    98  | 
        CGColorRelease(_realBGColor);
  | 
| 
jens@1
 | 
    99  | 
        _realBGColor = CGColorRetain(color);
  | 
| 
jens@1
 | 
   100  | 
        [self setNeedsDisplay];
  | 
| 
jens@1
 | 
   101  | 
    }
  | 
| 
jens@1
 | 
   102  | 
}
  | 
| 
jens@1
 | 
   103  | 
  | 
| 
jens@1
 | 
   104  | 
  | 
| 
jens@1
 | 
   105  | 
- (void) setBorderColor: (CGColorRef)color
  | 
| 
jens@1
 | 
   106  | 
{
 | 
| 
jens@1
 | 
   107  | 
    if( color != _borderColor ) {
 | 
| 
jens@1
 | 
   108  | 
        CGColorRelease(_borderColor);
  | 
| 
jens@1
 | 
   109  | 
        _borderColor = CGColorRetain(color);
  | 
| 
jens@1
 | 
   110  | 
        self.needsDisplayOnBoundsChange = (_borderWidth>0.0 && _borderColor!=NULL);
  | 
| 
jens@1
 | 
   111  | 
        [self setNeedsDisplay];
  | 
| 
jens@1
 | 
   112  | 
    }
  | 
| 
jens@1
 | 
   113  | 
}
  | 
| 
jens@1
 | 
   114  | 
  | 
| 
jens@1
 | 
   115  | 
  | 
| 
jens@1
 | 
   116  | 
- (void)drawInContext:(CGContextRef)ctx
  | 
| 
jens@1
 | 
   117  | 
{
 | 
| 
jens@1
 | 
   118  | 
    CGContextSaveGState(ctx);
  | 
| 
jens@1
 | 
   119  | 
  | 
| 
jens@1
 | 
   120  | 
    if( _realBGColor ) {
 | 
| 
jens@1
 | 
   121  | 
        CGRect interior = CGRectInset(self.bounds, _borderWidth,_borderWidth);
  | 
| 
jens@1
 | 
   122  | 
        CGContextSetFillColorWithColor(ctx, _realBGColor);
  | 
| 
jens@1
 | 
   123  | 
        if( _cornerRadius <= 0.0 ) {
 | 
| 
jens@1
 | 
   124  | 
            CGContextFillRect(ctx,interior);
  | 
| 
jens@1
 | 
   125  | 
        } else {
 | 
| 
jens@1
 | 
   126  | 
            CGContextBeginPath(ctx);
  | 
| 
jens@1
 | 
   127  | 
            AddRoundRect(ctx,interior,_cornerRadius);
  | 
| 
jens@1
 | 
   128  | 
            CGContextFillPath(ctx);
  | 
| 
jens@1
 | 
   129  | 
        }
  | 
| 
jens@1
 | 
   130  | 
    }
  | 
| 
jens@1
 | 
   131  | 
    
  | 
| 
jens@1
 | 
   132  | 
    if( _borderWidth > 0.0 && _borderColor!=NULL ) {
 | 
| 
jens@1
 | 
   133  | 
        CGRect border = CGRectInset(self.bounds, _borderWidth/2.0, _borderWidth/2.0);
  | 
| 
jens@1
 | 
   134  | 
        CGContextSetStrokeColorWithColor(ctx, _borderColor);
  | 
| 
jens@1
 | 
   135  | 
        CGContextSetLineWidth(ctx, _borderWidth);
  | 
| 
jens@1
 | 
   136  | 
        
  | 
| 
jens@1
 | 
   137  | 
        if( _cornerRadius <= 0.0 ) {
 | 
| 
jens@1
 | 
   138  | 
            CGContextStrokeRect(ctx,border);
  | 
| 
jens@1
 | 
   139  | 
        } else {
 | 
| 
jens@1
 | 
   140  | 
            CGContextBeginPath(ctx);
  | 
| 
jens@1
 | 
   141  | 
            AddRoundRect(ctx,border,_cornerRadius);
  | 
| 
jens@1
 | 
   142  | 
            CGContextStrokePath(ctx);
  | 
| 
jens@1
 | 
   143  | 
        }
  | 
| 
jens@1
 | 
   144  | 
    }
  | 
| 
jens@1
 | 
   145  | 
    
  | 
| 
jens@1
 | 
   146  | 
    CGContextRestoreGState(ctx);
  | 
| 
jens@1
 | 
   147  | 
}
  | 
| 
jens@1
 | 
   148  | 
  | 
| 
jens@1
 | 
   149  | 
  | 
| 
jens@1
 | 
   150  | 
#else
  | 
| 
jens@1
 | 
   151  | 
  | 
| 
jens@1
 | 
   152  | 
#pragma mark -
  | 
| 
jens@1
 | 
   153  | 
#pragma mark MAC OS VERSION:
  | 
| 
jens@1
 | 
   154  | 
  | 
| 
jens@1
 | 
   155  | 
  | 
| 
jens@1
 | 
   156  | 
- (id) copyWithZone: (NSZone*)zone
  | 
| 
jens@1
 | 
   157  | 
{
 | 
| 
jens@1
 | 
   158  | 
    // NSLayer isn't copyable, but it is archivable. So create a copy by archiving to
  | 
| 
jens@1
 | 
   159  | 
    // a temporary data block, then unarchiving a new layer from that block.
  | 
| 
jens@1
 | 
   160  | 
    
  | 
| 
jens@1
 | 
   161  | 
    // One complication is that, due to a bug in Core Animation, CALayer can't archive
  | 
| 
jens@1
 | 
   162  | 
    // a pattern-based CGColor. So as a workaround, clear the background before archiving,
  | 
| 
jens@1
 | 
   163  | 
    // then restore it afterwards.
  | 
| 
jens@1
 | 
   164  | 
    
  | 
| 
jens@1
 | 
   165  | 
    // Also, archiving a CALayer with an image in it leaks memory. (Filed as rdar://5786865 )
  | 
| 
jens@1
 | 
   166  | 
    // As a workaround, clear the contents before archiving, then restore.
  | 
| 
jens@1
 | 
   167  | 
    
  | 
| 
jens@1
 | 
   168  | 
    CGColorRef bg = CGColorRetain(self.backgroundColor);
  | 
| 
jens@1
 | 
   169  | 
    self.backgroundColor = NULL;
  | 
| 
jens@1
 | 
   170  | 
    id contents = [self.contents retain];
  | 
| 
jens@1
 | 
   171  | 
    self.contents = nil;
  | 
| 
jens@1
 | 
   172  | 
    
  | 
| 
jens@1
 | 
   173  | 
    NSData *data = [NSKeyedArchiver archivedDataWithRootObject: self];
  | 
| 
jens@1
 | 
   174  | 
    
  | 
| 
jens@1
 | 
   175  | 
    self.backgroundColor = bg;
  | 
| 
jens@1
 | 
   176  | 
    self.contents = contents;
  | 
| 
jens@1
 | 
   177  | 
  | 
| 
jens@1
 | 
   178  | 
    GGBLayer *clone = [NSKeyedUnarchiver unarchiveObjectWithData: data];
  | 
| 
jens@1
 | 
   179  | 
    clone.backgroundColor = bg;
  | 
| 
jens@1
 | 
   180  | 
    clone.contents = contents;
  | 
| 
jens@1
 | 
   181  | 
    CGColorRelease(bg);
  | 
| 
jens@1
 | 
   182  | 
    [contents release];
  | 
| 
jens@1
 | 
   183  | 
  | 
| 
jens@1
 | 
   184  | 
    return [clone retain];
  | 
| 
jens@1
 | 
   185  | 
}
  | 
| 
jens@1
 | 
   186  | 
  | 
| 
jens@1
 | 
   187  | 
  | 
| 
jens@1
 | 
   188  | 
#endif
  | 
| 
jens@1
 | 
   189  | 
  | 
| 
jens@1
 | 
   190  | 
  | 
| 
jens@1
 | 
   191  | 
@end
  |