Skip to content
Browse files

Initial revision.

Contains tint code, but it doesn't do anything clever with brightness of tint.
  • Loading branch information...
0 parents commit 1fadeb098a1030f0b0accf791b3db3e1e8dfe11c @AlanQuatermain committed Jun 30, 2009
Showing with 263 additions and 0 deletions.
  1. +1 −0 .gitignore
  2. +48 −0 AQGlassButton.h
  3. +214 −0 AQGlassButton.m
1 .gitignore
@@ -0,0 +1 @@
+.DS_Store
48 AQGlassButton.h
@@ -0,0 +1,48 @@
+/*
+ * AQGlassButton.h
+ * AQGlassButton
+ *
+ * Created by Jim Dovey on 3/6/2009.
+ *
+ * Copyright (c) 2009 Jim Dovey
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * Neither the name of the project's author nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#import <UIKit/UIKit.h>
+
+@interface AQGlassButton : UIButton <NSCoding>
+{
+ CGMutablePathRef _path;
+ CGGradientRef _gradient;
+ UIColor * _tintColor;
+}
+@property (nonatomic, retain) UIColor * tintColor;
+@end
214 AQGlassButton.m
@@ -0,0 +1,214 @@
+/*
+ * AQGlassButton.m
+ * AQGlassButton
+ *
+ * Created by Jim Dovey on 3/6/2009.
+ *
+ * Copyright (c) 2009 Jim Dovey
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * Neither the name of the project's author nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#import "AQGlassButton.h"
+
+@implementation AQGlassButton
+
+@synthesize tintColor=_tintColor;
+
+- (void) updatePath
+{
+ CGRect bounds = self.bounds;
+
+ if ( _path != NULL )
+ {
+ CGPathRelease( _path );
+ _path = NULL;
+ }
+
+ CGFloat cornerRadius = floorf( bounds.size.height * 0.2 );
+
+ _path = CGPathCreateMutable();
+ CGPathMoveToPoint( _path, NULL, CGRectGetMinX(bounds), CGRectGetMinY(bounds) + cornerRadius );
+ CGPathAddLineToPoint( _path, NULL, CGRectGetMinX(bounds), CGRectGetMaxY(bounds) - cornerRadius );
+ CGPathAddArcToPoint( _path, NULL, CGRectGetMinX(bounds), CGRectGetMaxY(bounds),
+ CGRectGetMinX(bounds) + cornerRadius, CGRectGetMaxY(bounds), cornerRadius );
+ CGPathAddLineToPoint( _path, NULL, CGRectGetMaxX(bounds) - cornerRadius, CGRectGetMaxY(bounds) );
+ CGPathAddArcToPoint( _path, NULL, CGRectGetMaxX(bounds), CGRectGetMaxY(bounds),
+ CGRectGetMaxX(bounds), CGRectGetMaxY(bounds) - cornerRadius, cornerRadius );
+ CGPathAddLineToPoint( _path, NULL, CGRectGetMaxX(bounds), CGRectGetMinY(bounds) + cornerRadius );
+ CGPathAddArcToPoint( _path, NULL, CGRectGetMaxX(bounds), CGRectGetMinY(bounds),
+ CGRectGetMaxX(bounds) - cornerRadius, CGRectGetMinY(bounds), cornerRadius );
+ CGPathAddLineToPoint( _path, NULL, CGRectGetMinX(bounds) + cornerRadius, CGRectGetMinY(bounds) );
+ CGPathAddArcToPoint( _path, NULL, CGRectGetMinX(bounds), CGRectGetMinY(bounds),
+ CGRectGetMinX(bounds), CGRectGetMinY(bounds) + cornerRadius, cornerRadius );
+ CGPathCloseSubpath( _path );
+}
+
+- (void) setup
+{
+ if ( _gradient != NULL )
+ CGGradientRelease( _gradient );
+
+ CGColorRef color = self.tintColor.CGColor;
+ CGColorSpaceRef space = CGColorGetColorSpace( color );
+
+ size_t numComponents = CGColorGetNumberOfComponents( color );
+ const CGFloat * srcComponents = CGColorGetComponents( color );
+ CGFloat tintAlpha = CGColorGetAlpha( color );
+
+ CGFloat * components = (CGFloat *) NSZoneMalloc( [self zone], numComponents * 5 * sizeof(CGFloat) );
+
+ int i, j;
+ CGFloat alphas[5] = {
+ 0.60 * tintAlpha,
+ 0.40 * tintAlpha,
+ 0.20 * tintAlpha,
+ 0.23 * tintAlpha,
+ 0.30 * tintAlpha
+ };
+ for ( i = 0; i < 5; i++ )
+ {
+ for ( j = 0; j < numComponents-1; j++ )
+ components[i*numComponents+j] = srcComponents[j];
+ components[i*numComponents+j] = alphas[i];
+ }
+ /*
+ for the default (grey) tint color, we'll ultimately have this:
+ CGFloat components[20] = {
+ 0.6, 0.6, 0.6, 0.6,
+ 0.6, 0.6, 0.6, 0.4,
+ 0.6, 0.6, 0.6, 0.2,
+ 0.6, 0.6, 0.6, 0.23,
+ 0.6, 0.6, 0.6, 0.3
+ };
+ */
+ CGFloat locations[5] = {
+ 1.0, 0.5, 0.499, 0.1, 0.0
+ };
+
+ _gradient = CGGradientCreateWithColorComponents( space, components, locations, 5 );
+ NSZoneFree( [self zone], components );
+
+ if ( !CGRectIsEmpty(self.bounds) )
+ [self updatePath];
+}
+
+- (id) initWithFrame: (CGRect) frameRect
+{
+ self = [super initWithFrame: frameRect];
+ if ( self == nil )
+ return ( nil );
+
+ _tintColor = [[UIColor alloc] initWithRed: 0.6 green: 0.6 blue: 0.6 alpha: 1.0];
+ [self setup];
+
+ return ( self );
+}
+
+- (id) initWithCoder: (NSCoder *) coder
+{
+ self = [super initWithCoder: coder];
+ if ( self == nil )
+ return ( nil );
+
+ _tintColor = [[coder decodeObjectForKey: @"tintColor"] retain];
+ if ( self.tintColor == nil )
+ _tintColor = [[UIColor alloc] initWithRed: 0.6 green: 0.6 blue: 0.6 alpha: 1.0];
+
+ [self setup];
+
+ return ( self );
+}
+
+- (void) dealloc
+{
+ CGPathRelease( _path );
+ CGGradientRelease( _gradient );
+ [_tintColor release];
+ [super dealloc];
+}
+
+- (void) encodeWithCoder: (NSCoder *) coder
+{
+ [super encodeWithCoder: coder];
+ [coder encodeObject: self.tintColor forKey: @"tintColor"];
+}
+
+- (void) setHighlighted: (BOOL) highlighted
+{
+ BOOL old = self.highlighted;
+ [super setHighlighted: highlighted];
+
+ if ( old != highlighted )
+ [self setNeedsDisplay];
+}
+
+- (void) setFrame: (CGRect) frame
+{
+ [super setFrame: frame];
+ [self updatePath];
+}
+
+- (void) setTintColor: (UIColor *) newColor
+{
+ [newColor retain];
+ [_tintColor release];
+ _tintColor = newColor;
+
+ // recreate the gradient as appropriate
+ [self setup];
+}
+
+- (void) drawRect: (CGRect) theRect
+{
+ [[UIColor darkGrayColor] setStroke];
+
+ [[UIColor clearColor] setFill];
+ UIRectFill( theRect );
+
+ if ( self.highlighted )
+ [[UIColor colorWithWhite: 1.0 alpha: 0.1] setFill];
+
+ CGContextRef ctx = UIGraphicsGetCurrentContext();
+
+ CGContextSetLineWidth( ctx, 1.0 );
+ CGContextBeginPath( ctx );
+ CGContextAddPath( ctx, _path );
+ CGContextDrawPath( ctx, kCGPathFillStroke );
+
+ CGContextBeginPath( ctx );
+ CGContextAddPath( ctx, _path );
+ CGContextClip( ctx );
+
+ CGRect bounds = self.bounds;
+ CGContextDrawLinearGradient( ctx, _gradient, CGPointMake(bounds.origin.x, CGRectGetMaxY(bounds)), bounds.origin, 0 );
+}
+
+@end

0 comments on commit 1fadeb0

Please sign in to comment.
Something went wrong with that request. Please try again.