diff --git a/PrettyExample.xcodeproj/project.pbxproj b/PrettyExample.xcodeproj/project.pbxproj index d150374..04b2b86 100644 --- a/PrettyExample.xcodeproj/project.pbxproj +++ b/PrettyExample.xcodeproj/project.pbxproj @@ -7,6 +7,7 @@ objects = { /* Begin PBXBuildFile section */ + 3F8D2269155435E40042B767 /* PrettyTabBarButton.m in Sources */ = {isa = PBXBuildFile; fileRef = 3F8D2268155435E40042B767 /* PrettyTabBarButton.m */; }; 572B2E6615348E1B0002228B /* RotableTabBarController.m in Sources */ = {isa = PBXBuildFile; fileRef = 572B2E6515348E1B0002228B /* RotableTabBarController.m */; }; 572B2E6A153496880002228B /* background.png in Resources */ = {isa = PBXBuildFile; fileRef = 572B2E68153496870002228B /* background.png */; }; 572B2E6B153496880002228B /* background@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 572B2E69153496870002228B /* background@2x.png */; }; @@ -19,6 +20,8 @@ 57360BDD14FF84F600343B7B /* MainWindow.xib in Resources */ = {isa = PBXBuildFile; fileRef = 57360BDC14FF84F600343B7B /* MainWindow.xib */; }; 57360BDF14FF889B00343B7B /* ExampleViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 57360BDE14FF889B00343B7B /* ExampleViewController.xib */; }; 57360BE114FF911200343B7B /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 57360BE014FF911200343B7B /* QuartzCore.framework */; }; + 57810A2F1557C01E00974D07 /* listButton.png in Resources */ = {isa = PBXBuildFile; fileRef = 57810A2D1557C01E00974D07 /* listButton.png */; }; + 57810A301557C01E00974D07 /* listButton@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 57810A2E1557C01E00974D07 /* listButton@2x.png */; }; 578998C41535E02000E06FCA /* PrettyCustomViewTableViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 578998B31535E02000E06FCA /* PrettyCustomViewTableViewCell.m */; }; 578998C51535E02000E06FCA /* PrettyGridTableViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 578998B51535E02000E06FCA /* PrettyGridTableViewCell.m */; }; 578998C61535E02000E06FCA /* PrettySegmentedControlTableViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 578998B71535E02000E06FCA /* PrettySegmentedControlTableViewCell.m */; }; @@ -36,6 +39,8 @@ /* End PBXBuildFile section */ /* Begin PBXFileReference section */ + 3F8D2267155435E40042B767 /* PrettyTabBarButton.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PrettyTabBarButton.h; sourceTree = ""; }; + 3F8D2268155435E40042B767 /* PrettyTabBarButton.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PrettyTabBarButton.m; sourceTree = ""; }; 572B2E6415348E1B0002228B /* RotableTabBarController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RotableTabBarController.h; sourceTree = ""; }; 572B2E6515348E1B0002228B /* RotableTabBarController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RotableTabBarController.m; sourceTree = ""; }; 572B2E68153496870002228B /* background.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = background.png; sourceTree = ""; }; @@ -53,6 +58,8 @@ 57360BDC14FF84F600343B7B /* MainWindow.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = MainWindow.xib; sourceTree = ""; }; 57360BDE14FF889B00343B7B /* ExampleViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = ExampleViewController.xib; sourceTree = ""; }; 57360BE014FF911200343B7B /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = System/Library/Frameworks/QuartzCore.framework; sourceTree = SDKROOT; }; + 57810A2D1557C01E00974D07 /* listButton.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = listButton.png; sourceTree = ""; }; + 57810A2E1557C01E00974D07 /* listButton@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "listButton@2x.png"; sourceTree = ""; }; 578998B21535E02000E06FCA /* PrettyCustomViewTableViewCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PrettyCustomViewTableViewCell.h; sourceTree = ""; }; 578998B31535E02000E06FCA /* PrettyCustomViewTableViewCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PrettyCustomViewTableViewCell.m; sourceTree = ""; }; 578998B41535E02000E06FCA /* PrettyGridTableViewCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PrettyGridTableViewCell.h; sourceTree = ""; }; @@ -153,6 +160,8 @@ 5735F8C214FD2FFC00DD7370 /* Supporting Files */ = { isa = PBXGroup; children = ( + 57810A2D1557C01E00974D07 /* listButton.png */, + 57810A2E1557C01E00974D07 /* listButton@2x.png */, 5735F8C314FD2FFC00DD7370 /* PrettyExample-Info.plist */, 5735F8C414FD2FFC00DD7370 /* InfoPlist.strings */, 5735F8C714FD2FFC00DD7370 /* main.m */, @@ -174,6 +183,8 @@ 578998C01535E02000E06FCA /* PrettyShadowPlainTableview.m */, 578998C11535E02000E06FCA /* PrettyTabBar.h */, 578998C21535E02000E06FCA /* PrettyTabBar.m */, + 3F8D2267155435E40042B767 /* PrettyTabBarButton.h */, + 3F8D2268155435E40042B767 /* PrettyTabBarButton.m */, EDA7DCAF1548EBD1002219BA /* PrettyToolbar.h */, EDA7DCB01548EBD1002219BA /* PrettyToolbar.m */, ); @@ -252,6 +263,8 @@ 572B2E6A153496880002228B /* background.png in Resources */, 572B2E6B153496880002228B /* background@2x.png in Resources */, EDA7DCB71548ED3F002219BA /* ModalViewController.xib in Resources */, + 57810A2F1557C01E00974D07 /* listButton.png in Resources */, + 57810A301557C01E00974D07 /* listButton@2x.png in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -277,6 +290,7 @@ 578998CB1535E02000E06FCA /* PrettyTabBar.m in Sources */, EDA7DCB11548EBD1002219BA /* PrettyToolbar.m in Sources */, EDA7DCB61548ED3F002219BA /* ModalViewController.m in Sources */, + 3F8D2269155435E40042B767 /* PrettyTabBarButton.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/PrettyExample/AppDelegate.m b/PrettyExample/AppDelegate.m index 25f9417..58a61a2 100644 --- a/PrettyExample/AppDelegate.m +++ b/PrettyExample/AppDelegate.m @@ -8,6 +8,7 @@ #import "AppDelegate.h" #import "ExampleViewController.h" +#import "PrettyTabBar.h" @implementation AppDelegate @@ -29,7 +30,7 @@ - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:( self.window.backgroundColor = [UIColor whiteColor]; self.window.rootViewController = self.tabBarController; - + ((PrettyTabBar *)self.tabBarController.tabBar).prettyTabBarButtons = YES; [self.window makeKeyAndVisible]; return YES; diff --git a/PrettyExample/MainWindow.xib b/PrettyExample/MainWindow.xib index 6f0a18f..0ceb445 100644 --- a/PrettyExample/MainWindow.xib +++ b/PrettyExample/MainWindow.xib @@ -53,6 +53,10 @@ Plain Table + + NSImage + listButton.png + IBCocoaTouchFramework @@ -303,7 +307,7 @@ - 24 + 25 0 @@ -314,6 +318,10 @@ YES 3 + + listButton.png + {22, 16} + 933 diff --git a/PrettyExample/listButton.png b/PrettyExample/listButton.png new file mode 100644 index 0000000..6c1d439 Binary files /dev/null and b/PrettyExample/listButton.png differ diff --git a/PrettyExample/listButton@2x.png b/PrettyExample/listButton@2x.png new file mode 100644 index 0000000..57ec489 Binary files /dev/null and b/PrettyExample/listButton@2x.png differ diff --git a/PrettyKit/PrettyDrawing.h b/PrettyKit/PrettyDrawing.h index bff338e..d8ba34e 100644 --- a/PrettyKit/PrettyDrawing.h +++ b/PrettyKit/PrettyDrawing.h @@ -27,7 +27,7 @@ // SOFTWARE. -#import +#import typedef enum { LinePositionTop = 0, @@ -40,6 +40,26 @@ typedef enum { @interface PrettyDrawing : NSObject +/** + Returns a CGMutablePathRef that is for a Rounded Rectangle in rect with corner radii radius. + */ +CGMutablePathRef PrettyKitCreateMutablePathForRoundedRect(CGRect rect, CGFloat radius); + +/** + Draws a rounded rectangle using the radius and fill color into a rect + */ ++ (void)drawRoundedRect:(CGRect)rect cornerRadius:(CGFloat)radius color:(UIColor *)color; + +/** + Draws a gradient into a context using a startPoint, endPOint and a from and to color + */ ++ (void)drawGradientForContext:(CGContextRef)context startPoint:(CGPoint)startPoint endPoint:(CGPoint)endPoint fromColor:(UIColor *)fromColor toColor:(UIColor *)toColor; + +/** + Draws a rounded rect with a gradient and a corner radius into a rect + */ ++ (void)drawGradientRoundedRect:(CGRect)rect cornerRadius:(CGFloat)radius fromColor:(UIColor *)from toColor:(UIColor *)to; + /** Draws a gradient with the given colors into the given rect. */ @@ -79,6 +99,12 @@ typedef enum { */ - (void) dropShadowWithOpacity:(float)opacity; +/** Drops a shadow with the given opacity and offset. + + @warning This method uses the UILayer shadow properties. + */ +- (void) dropShadowOffset:(CGSize)offset withOpacity:(float)opacity; + @end @@ -92,4 +118,11 @@ typedef enum { @return A new autoreleased UIColor instance. */ + (UIColor *) colorWithHex:(int)hex; +/** Converts the color to an RGB colorspace and puts values of the components into the components parameter + + @param Pointer to a CGFloat array of the most 4 elements + + */ +-(void)getRGBColorComponents:(CGFloat [4])components; + @end \ No newline at end of file diff --git a/PrettyKit/PrettyDrawing.m b/PrettyKit/PrettyDrawing.m index 0841c88..cced086 100644 --- a/PrettyKit/PrettyDrawing.m +++ b/PrettyKit/PrettyDrawing.m @@ -32,30 +32,85 @@ @implementation PrettyDrawing -+ (void) drawGradient:(CGRect)rect fromColor:(UIColor *)from toColor:(UIColor *)to { - CGContextRef ctx = UIGraphicsGetCurrentContext(); - CGContextSaveGState(ctx); +CGMutablePathRef PrettyKitCreateMutablePathForRoundedRect(CGRect rect, CGFloat radius) { + CGMutablePathRef path = CGPathCreateMutable(); + CGPathAddArc(path, NULL, rect.origin.x + radius, rect.origin.y + radius, radius, (180) * M_PI/180, (-90) * M_PI/180, 0); + CGPathAddArc(path, NULL, rect.origin.x + rect.size.width - radius, rect.origin.y + radius, radius, (-90) * M_PI/180, (0) * M_PI/180, 0); + CGPathAddArc(path, NULL, rect.origin.x + rect.size.width - radius, rect.origin.y + rect.size.height - radius, radius, (0) * M_PI/180, (-270) * M_PI/180, 0); + CGPathAddArc(path, NULL, rect.origin.x + radius, rect.origin.y + rect.size.height - radius, radius, (-270) * M_PI/180, (-180) * M_PI/180, 0); + + return path; +} + ++ (void)drawRoundedRect:(CGRect)rect cornerRadius:(CGFloat)radius color:(UIColor *)color { + CGContextRef context = UIGraphicsGetCurrentContext(); + CGContextSaveGState(context); - CGContextAddRect(ctx, rect); - CGContextClip(ctx); + CGMutablePathRef path = PrettyKitCreateMutablePathForRoundedRect(rect, radius); + CGContextAddPath(context, path); + + [color setFill]; + CGContextDrawPath(context, kCGPathFill); + + CGContextRestoreGState(context); + CGPathRelease(path); +} + ++ (void)drawGradientRoundedRect:(CGRect)rect cornerRadius:(CGFloat)radius fromColor:(UIColor *)from toColor:(UIColor *)to { + CGContextRef context = UIGraphicsGetCurrentContext(); + CGContextSaveGState(context); + + CGMutablePathRef path = PrettyKitCreateMutablePathForRoundedRect(rect, radius); + CGContextAddPath(context, path); + CGContextClip(context); + [PrettyDrawing drawGradientForContext:context + startPoint:CGPointMake(rect.origin.x + rect.size.width/2, rect.origin.y) + endPoint:CGPointMake(rect.origin.x + rect.size.width/2, rect.origin.y + rect.size.height) + fromColor:from + toColor:to]; + + CGContextRestoreGState(context); + CGPathRelease(path); + +} + ++ (void)drawGradientForContext:(CGContextRef)context startPoint:(CGPoint)startPoint endPoint:(CGPoint)endPoint fromColor:(UIColor *)fromColor toColor:(UIColor *)toColor { CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); - CGFloat locations[] = { 0.0, 1.0 }; - CGColorRef startColor = from.CGColor; - CGColorRef endColor = to.CGColor; - NSArray *colors = [NSArray arrayWithObjects:(id)startColor, (id)endColor, nil]; + CGFloat locations[] = {0.0, 1.0}; - CGGradientRef gradient = CGGradientCreateWithColors(colorSpace, - (CFArrayRef) colors, locations); + // iOS 4.3 safe way of drawing gradients. not as awesome as CGGradientCreateWithColors + CGFloat fromComponents[4]; + [fromColor getRGBColorComponents:fromComponents]; - CGPoint startPoint = CGPointMake(CGRectGetMidX(rect), CGRectGetMinY(rect)); - CGPoint endPoint = CGPointMake(CGRectGetMidX(rect), CGRectGetMaxY(rect)); + CGFloat toComponents[4]; + [toColor getRGBColorComponents:toComponents]; - CGContextDrawLinearGradient(ctx, gradient, startPoint, endPoint, 0); + CGFloat colors[8] = { fromComponents[0], fromComponents[1], fromComponents[2], fromComponents[3], + toComponents[0], toComponents[1], toComponents[2], toComponents[3]}; + + CGGradientRef gradient = CGGradientCreateWithColorComponents(colorSpace, colors, locations, 2); + + ///////////////////////////////////////////////////////////////////////// + + CGContextDrawLinearGradient(context, gradient, startPoint, endPoint, 0); CGGradientRelease(gradient); CGColorSpaceRelease(colorSpace); +} + ++ (void) drawGradient:(CGRect)rect fromColor:(UIColor *)from toColor:(UIColor *)to { + CGContextRef ctx = UIGraphicsGetCurrentContext(); + CGContextSaveGState(ctx); + CGContextAddRect(ctx, rect); + CGContextClip(ctx); + + CGPoint startPoint = CGPointMake(CGRectGetMidX(rect), CGRectGetMinY(rect)); + CGPoint endPoint = CGPointMake(CGRectGetMidX(rect), CGRectGetMaxY(rect)); + + [PrettyDrawing drawGradientForContext:ctx startPoint:startPoint endPoint:endPoint fromColor:from toColor:to]; + CGContextRestoreGState(ctx); } @@ -118,13 +173,19 @@ + (void) drawGradient:(CGGradientRef)gradient rect:(CGRect)rect @implementation UIView (PrettyKit) -- (void) dropShadowWithOpacity:(float)opacity { +- (void) dropShadowOffset:(CGSize)offset withOpacity:(float)opacity { self.layer.masksToBounds = NO; - self.layer.shadowOffset = CGSizeMake(0, 0); + self.layer.shadowOffset = offset; self.layer.shadowOpacity = opacity; self.layer.shadowPath = [UIBezierPath bezierPathWithRect:self.bounds].CGPath; } +- (void) dropShadowWithOpacity:(float)opacity { + [self dropShadowOffset:CGSizeMake(0, 0) withOpacity:opacity]; + +} + + @end @@ -137,5 +198,38 @@ + (UIColor *) colorWithHex:(int)hex { blue:((float)(hex & 0xFF))/255.0 alpha:1.0]; } +-(void)getRGBColorComponents:(CGFloat [4])components { + if (CGColorGetNumberOfComponents([self CGColor]) == 4) { + const CGFloat *actualComponents = CGColorGetComponents([self CGColor]); + + components[0] = actualComponents[0]; + components[1] = actualComponents[1]; + components[2] = actualComponents[2]; + components[3] = actualComponents[3]; + + return; + } + + components[3] = CGColorGetAlpha([self CGColor]); + + CGColorSpaceRef rgbColorSpace = CGColorSpaceCreateDeviceRGB(); + unsigned char resultingPixel[4]; + CGContextRef context = CGBitmapContextCreate(&resultingPixel, + 1, + 1, + 8, + 4, + rgbColorSpace, + kCGImageAlphaNoneSkipLast); + CGContextSetFillColorWithColor(context, [self CGColor]); + CGContextFillRect(context, CGRectMake(0, 0, 1, 1)); + CGContextRelease(context); + CGColorSpaceRelease(rgbColorSpace); + + for (int component = 0; component < 3; component++) { + components[component] = resultingPixel[component] / 255.0f; + } +} + @end \ No newline at end of file diff --git a/PrettyKit/PrettyNavigationBar.m b/PrettyKit/PrettyNavigationBar.m index b53d2a1..5bc58e1 100644 --- a/PrettyKit/PrettyNavigationBar.m +++ b/PrettyKit/PrettyNavigationBar.m @@ -36,7 +36,7 @@ @implementation PrettyNavigationBar @synthesize shadowOpacity, gradientEndColor, gradientStartColor, topLineColor, bottomLineColor, roundedCornerRadius, roundedCornerColor; -#define default_shadow_opacity 0.5 +#define default_shadow_opacity 0.5 #define default_gradient_end_color [UIColor colorWithHex:0x297CB7] #define default_gradient_start_color [UIColor colorWithHex:0x53A4DE] #define default_top_line_color [UIColor colorWithHex:0x84B7D5] diff --git a/PrettyKit/PrettyTabBar.h b/PrettyKit/PrettyTabBar.h index e20260f..da7ced3 100644 --- a/PrettyKit/PrettyTabBar.h +++ b/PrettyKit/PrettyTabBar.h @@ -43,6 +43,16 @@ */ @interface PrettyTabBar : UITabBar +/** Specifies the navigation bar upwards shadow's opacity. + + By default is `0.5`. */ +@property (nonatomic, assign) float upwardsShadowOpacity; + +/** Specifies the navigation bar downwards shadow's opacity. + + By default is `0.5`. */ +@property (nonatomic, assign) float downwardsShadowOpacity; + /** Specifies the gradient's start color. By default is a black tone. */ @@ -58,4 +68,118 @@ By default is a black tone. */ @property (nonatomic, retain) UIColor *separatorLineColor; +///////////////////////////////////////////////////////////////////////////// +// Pretty Tab Bar Button Implementation & Customization +///////////////////////////////////////////////////////////////////////////// + +/** Specifies that the PrettyTabBarButtons that should be used is of the iOS 6 styling + that stretches from the bottom to the top of the bar + + By default is NO. */ +@property (nonatomic) BOOL prettyStretchedTabBarButtons; + +/** Specifies that PrettyTabBarButtons should be used instead of the default UITabBarButtons + + By default is NO. */ +@property (nonatomic) BOOL prettyTabBarButtons; + +/** Specifies that images to display when a button is selected. + Use [NSNull null] if that particular button should use the gradient tints specified. + Otherwise supply a UIImage of the appropriate size. + + Images must be added at the same index that the relevant UITabBarItem's index + + By default is `nil`. */ +@property (nonatomic, copy) NSArray *prettyButtonHighlightedImages; + +/** Specifies the corner radius for the highlight's gradient (when selected) + + By default is `3.0`. */ +@property (readwrite) CGFloat prettyButtonHighlightCornerRadius; + +/** Specifies the start color for the gradient tint over the image when selected + + By default is `[UIColor colorWithRed:0.276 green:0.733 blue:1.000 alpha:1.000]`. */ +@property (nonatomic, retain) UIColor *prettyButtonHighlightedImageGradientStartColor; + +/** Specifies the end color for the gradient tint over the image when selected + + By default is `[UIColor colorWithRed:0.028 green:0.160 blue:0.332 alpha:1.000]`. */ +@property (nonatomic, retain) UIColor *prettyButtonHighlightedImageGradientEndColor; + +/** Specifies the font to use for the title of the button + + By default is `[UIFont fontWithName:@"HelveticaNeue-Bold" size:10]`. */ +@property (nonatomic, retain) UIFont *prettyButtonTitleFont; + +/** Specifies the color for the title of the button + + By default is `[UIColor colorWithWhite:0.2 alpha:1.0]`. */ +@property (nonatomic, retain) UIColor *prettyButtonTitleTextColor; + +/** Specifies the color for the title of the button when its been selected + + By default is `[UIColor colorWithWhite:0.90 alpha:1.0]`. */ +@property (nonatomic, retain) UIColor *prettyButtonTitleHighlightedTextColor; + +/** Specifies the opacity of the title's shadow + + By default is `0.5`. */ +@property (nonatomic) CGFloat prettyButtonTitleTextShadowOpacity; + +/** Specifies the offset for the title's shadow + + By default is `CGSizeMake(0,-1)`. */ +@property (nonatomic) CGSize prettyButtonTitleTextShadowOffset; + +/** Specifies the start color for the highlight's gradient (when selected) + + By default is `[UIColor colorWithWhite:0.4 alpha:1.0]`. */ +@property (nonatomic, retain) UIColor *prettyButtonHighlightGradientStartColor; + +/** Specifies the end color for the highlight's gradient (when selected) + + By default is `[UIColor colorWithWhite:0.1 alpha:1.0]`. */ +@property (nonatomic, retain) UIColor *prettyButtonHighlightGradientEndColor; + +/** Specifies the image to use in place of the highlight gradient. + + By default is `nil`. */ +@property (nonatomic, retain) UIImage *prettyButtonHighlightImage; + +/** Specifies the border color for the badge + + By default is `[UIColor whiteColor]`. */ +@property (nonatomic, retain) UIColor *prettyButtonBadgeBorderColor; + +/** Specifies the start color for the badge's gradient + + By default is `[UIColor colorWithRed:1.000 green:0.000 blue:0.000 alpha:1.000]`. */ +@property (nonatomic, retain) UIColor *prettyButtonBadgeGradientStartColor; + +/** Specifies the end color for the badge's gradient + + By default is `[UIColor colorWithRed:0.6 green:0.000 blue:0.000 alpha:1.000]`. */ +@property (nonatomic, retain) UIColor *prettyButtonBadgeGradientEndColor; + +/** Specifies the shadow opacity for the badge + + By default is `0.75`. */ +@property (nonatomic) CGFloat prettyButtonBadgeShadowOpacity; + +/** Specifies the shadow offset for the badge + + By default is `CGSizeMake(0,2)`. */ +@property (nonatomic) CGSize prettyButtonBadgeShadowOffset; + +/** Specifies the font used for the value of the badge + + By default is `[UIFont fontWithName:@"HelveticaNeue-Bold" size:11]`. */ +@property (nonatomic, retain) UIFont *prettyButtonBadgeFont; + +/** Specifies the color used for the text in the badge's value + + By default is `[UIColor whiteColor]`. */ +@property (nonatomic, retain) UIColor *prettyButtonBadgeTextColor; + @end diff --git a/PrettyKit/PrettyTabBar.m b/PrettyKit/PrettyTabBar.m index 3bf8514..d552593 100644 --- a/PrettyKit/PrettyTabBar.m +++ b/PrettyKit/PrettyTabBar.m @@ -29,19 +29,84 @@ #import "PrettyTabBar.h" #import "PrettyDrawing.h" +#import "PrettyTabBarButton.h" -#define default_gradient_start_color [UIColor colorWithHex:0x444444] -#define default_gradient_end_color [UIColor colorWithHex:0x060606] -#define default_separator_line_color [UIColor colorWithHex:0x666666] +#define default_upwards_shadow_opacity 0.5 +#define default_downwards_shadow_opacity 0.5 +#define default_gradient_start_color [UIColor colorWithHex:0x444444] +#define default_gradient_end_color [UIColor colorWithHex:0x060606] +#define default_separator_line_color [UIColor colorWithHex:0x666666] + +// pretty buttons +#define default_text_shadow_offset CGSizeMake(0,-1) +#define default_text_shadow_opacity 0.5 +#define default_font [UIFont boldSystemFontOfSize:10] +#define default_text_color [UIColor colorWithWhite:0.5 alpha:1.0] +#define default_highlighted_text_color [UIColor colorWithWhite:0.90 alpha:1.0] +#define default_badge_font [UIFont boldSystemFontOfSize:11] +#define default_badge_gradient_start_color [UIColor colorWithRed:1.000 green:0.000 blue:0.000 alpha:1.000] +#define default_badge_gradient_end_color [UIColor colorWithRed:0.6 green:0.000 blue:0.000 alpha:1.000] +#define default_badge_border_color [UIColor whiteColor] +#define default_badge_shadow_opacity 0.75 +#define default_badge_shadow_offset CGSizeMake(0,2) +#define default_badge_text_color [UIColor whiteColor] +#define default_highlight_corner_radius 3.0 +#define default_highlight_gradient_start_color [UIColor colorWithWhite:0.35 alpha:1.0] +#define default_highlight_gradient_end_color [UIColor colorWithWhite:0.2 alpha:1.0] +#define default_highlighted_image_gradient_start_color [UIColor colorWithRed:0.276 green:0.733 blue:1.000 alpha:1.000] +#define default_highlighted_image_gradient_end_color [UIColor colorWithRed:0.028 green:0.160 blue:0.332 alpha:1.000] + +@interface PrettyTabBar (/* Private Methods */) +@property (nonatomic, retain) NSMutableArray *_prettyTabBarButtons; +@property (nonatomic, retain) NSMutableArray *_originalTabBarButtons; +-(void)_prettyTabBarButtonTapped:(id)sender; +-(UIImage *)_imageForPrettyButtonImagesOfIndex:(NSInteger)index; +-(void)_setupTabBarSubviews; +@end @implementation PrettyTabBar -@synthesize gradientStartColor, gradientEndColor, separatorLineColor; +@synthesize upwardsShadowOpacity, downwardsShadowOpacity, gradientStartColor, gradientEndColor, separatorLineColor; +@synthesize prettyTabBarButtons, prettyStretchedTabBarButtons; + +@synthesize prettyButtonHighlightedImageGradientStartColor, prettyButtonHighlightedImageGradientEndColor, prettyButtonHighlightedImages; +@synthesize prettyButtonTitleFont, prettyButtonTitleTextColor, prettyButtonTitleHighlightedTextColor, prettyButtonTitleTextShadowOpacity, prettyButtonTitleTextShadowOffset; +@synthesize prettyButtonHighlightGradientStartColor, prettyButtonHighlightGradientEndColor, prettyButtonHighlightImage, prettyButtonHighlightCornerRadius; +@synthesize prettyButtonBadgeBorderColor, prettyButtonBadgeGradientStartColor, prettyButtonBadgeGradientEndColor, prettyButtonBadgeShadowOpacity, prettyButtonBadgeShadowOffset, prettyButtonBadgeFont, prettyButtonBadgeTextColor; + +@synthesize _prettyTabBarButtons = __prettyTabBarButtons, _originalTabBarButtons = __originalTabBarButtons; + +#pragma mark - Object Life Cycle - (void) dealloc { + + if (self.prettyTabBarButtons) { + for (UITabBarItem *item in self.items) + [item removeObserver:self forKeyPath:@"badgeValue"]; + } + self.gradientStartColor = nil; self.gradientEndColor = nil; self.separatorLineColor = nil; + self._originalTabBarButtons = nil; + self._prettyTabBarButtons = nil; + + self.prettyButtonHighlightedImages = nil; + + self.prettyButtonHighlightedImageGradientStartColor = nil; + self.prettyButtonHighlightedImageGradientEndColor = nil; + self.prettyButtonTitleFont = nil; + self.prettyButtonTitleTextColor = nil; + self.prettyButtonTitleHighlightedTextColor = nil; + self.prettyButtonBadgeBorderColor = nil; + self.prettyButtonBadgeGradientStartColor = nil; + self.prettyButtonBadgeGradientEndColor = nil; + self.prettyButtonBadgeFont = nil; + self.prettyButtonBadgeTextColor = nil; + self.prettyButtonHighlightImage = nil; + self.prettyButtonHighlightGradientStartColor = nil; + self.prettyButtonHighlightGradientEndColor = nil; + [super dealloc]; } @@ -49,9 +114,39 @@ - (void) initializeVars { self.contentMode = UIViewContentModeRedraw; + self.prettyTabBarButtons = NO; + self.prettyStretchedTabBarButtons = NO; + + self.upwardsShadowOpacity = default_upwards_shadow_opacity; + self.downwardsShadowOpacity = default_downwards_shadow_opacity; self.gradientStartColor = default_gradient_start_color; self.gradientEndColor = default_gradient_end_color; self.separatorLineColor = default_separator_line_color; + + // pretty button stuff + self._prettyTabBarButtons = [NSMutableArray arrayWithCapacity:5]; + self._originalTabBarButtons = [NSMutableArray arrayWithCapacity:0]; + self.prettyButtonHighlightedImages = nil; + + self.prettyButtonHighlightCornerRadius = default_highlight_corner_radius; + self.prettyButtonHighlightedImageGradientStartColor = default_highlighted_image_gradient_start_color; + self.prettyButtonHighlightedImageGradientEndColor = default_highlighted_image_gradient_end_color; + self.prettyButtonTitleFont = default_font; + self.prettyButtonTitleTextColor = default_text_color; + self.prettyButtonTitleHighlightedTextColor = default_highlighted_text_color; + self.prettyButtonTitleTextShadowOpacity = default_text_shadow_opacity; + self.prettyButtonTitleTextShadowOffset = default_text_shadow_offset; + self.prettyButtonBadgeBorderColor = default_badge_border_color; + self.prettyButtonBadgeGradientStartColor = default_badge_gradient_start_color; + self.prettyButtonBadgeGradientEndColor = default_badge_gradient_end_color; + self.prettyButtonBadgeShadowOffset = default_badge_shadow_offset; + self.prettyButtonBadgeShadowOpacity = default_badge_shadow_opacity; + self.prettyButtonBadgeFont = default_badge_font; + self.prettyButtonBadgeTextColor = default_badge_text_color; + self.prettyButtonHighlightImage = nil; + self.prettyButtonHighlightGradientStartColor = default_highlight_gradient_start_color; + self.prettyButtonHighlightGradientEndColor = default_highlight_gradient_end_color; + } - (id)initWithCoder:(NSCoder *)coder { @@ -79,12 +174,242 @@ - (id)init { return self; } +#pragma mark - Overrides to handle internal PrettyTabBarButton + +-(void)setItems:(NSArray *)items { + [super setItems:items]; + + [self _setupTabBarSubviews]; + [self setNeedsLayout]; +} + +-(void)setItems:(NSArray *)items animated:(BOOL)animated { + [super setItems:items animated:animated]; + + [self _setupTabBarSubviews]; + [self setNeedsLayout]; +} + +-(void)setSelectedItem:(UITabBarItem *)selectedItem { + [super setSelectedItem:selectedItem]; + + [self _setupTabBarSubviews]; + [self setNeedsLayout]; +} + + +-(void)_setupTabBarSubviews { + if (self.prettyTabBarButtons) { + // changing from original to pretty implementation + + // remove views that are not prettytabbarbuttons + // they are usually the original buttons so add them to temp storage + for (UIView *view in self.subviews) { + if (![view isKindOfClass:[PrettyTabBarButton class]]) + [__originalTabBarButtons addObject:view]; + + [view removeFromSuperview]; + } + + PrettyTabBarButton *button = nil; + // iterate over the data objects (UITabBarItem) and create the + // pretty tabbar buttons that they represent and position them + // in the view. + // we leave setting of properties to the laying out of subviews + // where its always supposed to be anyways + NSUInteger i = 0; + + for (UITabBarItem *item in self.items) { + [item addObserver:self forKeyPath:@"badgeValue" options:NSKeyValueObservingOptionNew context:item]; + + button = [[PrettyTabBarButton alloc] initWithTitle:item.title image:item.image tag:i]; + button.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth; + button.stretchedButton = self.prettyStretchedTabBarButtons; + + [button addTarget:self action:@selector(_prettyTabBarButtonTapped:) forControlEvents:UIControlEventTouchUpInside]; + + if (item == self.selectedItem) { + button.selected = YES; + } else { + button.selected = NO; + } + + [self addSubview:button]; + [__prettyTabBarButtons addObject:button]; + [button release]; + i++; + } + + + } else { + // changing from pretty to original implementation + + // remove observation status and remove the object from super view + NSUInteger i = 0; + + for (UITabBarItem *item in self.items) { + if ([__prettyTabBarButtons count] > 0) { + [[__prettyTabBarButtons objectAtIndex:i] removeFromSuperview]; + [item removeObserver:self forKeyPath:@"badgeValue"]; + } + + i++; + } + + [__prettyTabBarButtons removeAllObjects]; + + // lets add all the original buttons back into the view! + for (UIView *view in self._originalTabBarButtons) { + [self addSubview:view]; + } + + [__originalTabBarButtons removeAllObjects]; + + } +} + +-(void)setPrettyTabBarButtons:(BOOL)prettyTabBarButtons_ { + + // we should only change the status if its different + + if (prettyTabBarButtons != prettyTabBarButtons_) { + + // set the status of our internal representation + prettyTabBarButtons = prettyTabBarButtons_; + + [self _setupTabBarSubviews]; + + // finally, layout if there is a superview, ie. our view has been + // added as a view somewhere + if (self.superview) + [self setNeedsLayout]; + } + +} + +-(void)_prettyTabBarButtonTapped:(id)sender { + if (self.prettyTabBarButtons) { + for (PrettyTabBarButton *button in __prettyTabBarButtons) { + button.selected = NO; + } + + ((PrettyTabBarButton *)sender).selected = YES; + + if ([sender isKindOfClass:[PrettyTabBarButton class]]) { + if ([self.delegate isKindOfClass:[UITabBarController class]]) { + [((UITabBarController *)self.delegate) setSelectedIndex:((PrettyTabBarButton *)sender).tag]; + } + } + } +} + +-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { + + if (([keyPath isEqualToString:@"badgeValue"]) && (self.prettyTabBarButtons)) { + UITabBarItem *item = (UITabBarItem *)context; + NSUInteger index = [self.items indexOfObject:item]; + + if ((index != NSNotFound) && ([self._prettyTabBarButtons count] > 0)) + [[self._prettyTabBarButtons objectAtIndex:index] setBadgeValue:[change objectForKey:NSKeyValueChangeNewKey]]; + + } else { + @try { + [super observeValueForKeyPath:keyPath ofObject:object change:change context:context]; + } + @catch (NSException *exception) { } + } +} + +#pragma mark - Display +-(UIImage *)_imageForPrettyButtonImagesOfIndex:(NSInteger)index { + if ([self.prettyButtonHighlightedImages count] == 0) + return nil; + + id image = [self.prettyButtonHighlightedImages objectAtIndex:index]; + + if ([image isKindOfClass:[NSNull class]]) + return nil; + + return image; +} + +-(void)layoutSubviews { + + // make sure item count is not greater than 5. as we didn't + // cater for customization of items. + if ([self.items count] > 5) + self.prettyTabBarButtons = NO; + + [super layoutSubviews]; + + // so if we are the right mode and there are actual data objects + // lets go ahead and layout the pretty buttons + if (self.prettyTabBarButtons) { + PrettyTabBarButton *button = nil; + NSUInteger i = 0; + + // set frame and set all properties! + for (UITabBarItem *item in self.items) { + if ([self._prettyTabBarButtons count] == 0) + break; + + button = [self._prettyTabBarButtons objectAtIndex:i]; + if (self.prettyStretchedTabBarButtons) { + button.frame = CGRectMake(i * (self.frame.size.width/[self.items count]), 0, (self.frame.size.width/[self.items count]) - 1, self.frame.size.height); + } else { + button.frame = CGRectMake(i * (self.frame.size.width/[self.items count]), 0.5, (self.frame.size.width/[self.items count]) - 1, self.frame.size.height); + } + + [self addSubview:button]; + + // set button properties + button.font = self.prettyButtonTitleFont; + button.textColor = self.prettyButtonTitleTextColor; + button.highlightedTextColor = self.prettyButtonTitleHighlightedTextColor; + button.textShadowOpacity = self.prettyButtonTitleTextShadowOpacity; + button.textShadowOffset = self.prettyButtonTitleTextShadowOffset; + button.badgeBorderColor = self.prettyButtonBadgeBorderColor; + button.badgeGradientStartColor = self.prettyButtonBadgeGradientStartColor; + button.badgeGradientEndColor = self.prettyButtonBadgeGradientEndColor; + button.badgeShadowOffset = self.prettyButtonBadgeShadowOffset; + button.badgeShadowOpacity = self.prettyButtonBadgeShadowOpacity; + button.badgeFont = self.prettyButtonBadgeFont; + button.badgeTextColor = self.prettyButtonBadgeTextColor; + button.highlightImage = self.prettyButtonHighlightImage; + button.highlightGradientStartColor = self.prettyButtonHighlightGradientStartColor; + button.highlightGradientEndColor = self.prettyButtonHighlightGradientEndColor; + button.highlightedImage = [self _imageForPrettyButtonImagesOfIndex:i]; + button.highlightedImageGradientStartColor = self.prettyButtonHighlightedImageGradientStartColor; + button.highlightedImageGradientEndColor = self.prettyButtonHighlightedImageGradientEndColor; + button.highlightCornerRadius = self.prettyButtonHighlightCornerRadius; + button.stretchedButton = self.prettyStretchedTabBarButtons; + + button.selected = NO; + button.badgeValue = item.badgeValue; + button.title = item.title; + button.image = item.image; + + if (item == self.selectedItem) + button.selected = YES; + + i++; + } + + } + +} - (void) drawRect:(CGRect)rect { [super drawRect:rect]; + + if (self.upwardsShadowOpacity > 0) + [self dropShadowOffset:CGSizeMake(0, -1) withOpacity:self.upwardsShadowOpacity]; + + if (self.downwardsShadowOpacity > 0) + [self dropShadowOffset:CGSizeMake(0, 0) withOpacity:self.downwardsShadowOpacity]; [PrettyDrawing drawGradient:rect fromColor:self.gradientStartColor toColor:self.gradientEndColor]; - [PrettyDrawing drawLineAtHeight:0.5 rect:rect color:self.separatorLineColor width:2.5]; + [PrettyDrawing drawLineAtHeight:0 rect:rect color:self.separatorLineColor width:0.5]; } @end diff --git a/PrettyKit/PrettyTabBarButton.h b/PrettyKit/PrettyTabBarButton.h new file mode 100644 index 0000000..f24b6be --- /dev/null +++ b/PrettyKit/PrettyTabBarButton.h @@ -0,0 +1,153 @@ +// +// PrettyTabBarButton.h +// PrettyExample +// +// Created by Jeremy Foo on 4/5/12. + +// Copyright (c) 2012 Jeremy Foo. (@echoz) +// http://ornyx.net +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of +// this software and associated documentation files (the "Software"), to deal in +// the Software without restriction, including without limitation the rights to +// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +// the Software, and to permit persons to whom the Software is furnished to do so, +// subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#import + +@interface PrettyTabBarButton : UIControl + +/** Specifies the tabbar button should be stretched, a la iOS 6 styling + + By default is `NO`. */ +@property (readwrite) BOOL stretchedButton; + +/** Specifies the image to use when the Button is selected. If it is not specified, the button will use the normal image in a gradient tint that is specified. + + By default is `nil`. */ +@property (nonatomic, retain) UIImage *highlightedImage; + +/** Specifies the start color for the gradient tint over the image when selected + + By default is `[UIColor colorWithRed:0.276 green:0.733 blue:1.000 alpha:1.000]`. */ +@property (nonatomic, retain) UIColor *highlightedImageGradientStartColor; + +/** Specifies the end color for the gradient tint over the image when selected + + By default is `[UIColor colorWithRed:0.028 green:0.160 blue:0.332 alpha:1.000]`. */ +@property (nonatomic, retain) UIColor *highlightedImageGradientEndColor; + +/** Specifies the font to use for the title of the button + + By default is `[UIFont fontWithName:@"HelveticaNeue-Bold" size:10]`. */ +@property (nonatomic, retain) UIFont *font; + +/** Specifies the color for the title of the button + + By default is `[UIColor colorWithWhite:0.2 alpha:1.0]`. */ +@property (nonatomic, retain) UIColor *textColor; + +/** Specifies the color for the title of the button when its been selected + + By default is `[UIColor colorWithWhite:0.90 alpha:1.0]`. */ +@property (nonatomic, retain) UIColor *highlightedTextColor; + +/** Specifies the opacity of the title's shadow + + By default is `0.5`. */ +@property (nonatomic) CGFloat textShadowOpacity; + +/** Specifies the offset for the title's shadow + + By default is `CGSizeMake(0,-1)`. */ +@property (nonatomic) CGSize textShadowOffset; + +/** Specifies the corner radius for the highlight's gradient (when selected) + + By default is `3.0`. */ +@property (readwrite) CGFloat highlightCornerRadius; + +/** Specifies the start color for the highlight's gradient (when selected) + + By default is `[UIColor colorWithWhite:0.4 alpha:1.0]`. */ +@property (nonatomic, retain) UIColor *highlightGradientStartColor; + +/** Specifies the end color for the highlight's gradient (when selected) + + By default is `[UIColor colorWithWhite:0.1 alpha:1.0]`. */ +@property (nonatomic, retain) UIColor *highlightGradientEndColor; + +/** Specifies the image to use in place of the highlight gradient. + + By default is `nil`. */ +@property (nonatomic, retain) UIImage *highlightImage; + +/** Specifies the border color for the badge + + By default is `[UIColor whiteColor]`. */ +@property (nonatomic, retain) UIColor *badgeBorderColor; + +/** Specifies the start color for the badge's gradient + + By default is `[UIColor colorWithRed:1.000 green:0.000 blue:0.000 alpha:1.000]`. */ +@property (nonatomic, retain) UIColor *badgeGradientStartColor; + +/** Specifies the end color for the badge's gradient + + By default is `[UIColor colorWithRed:0.6 green:0.000 blue:0.000 alpha:1.000]`. */ +@property (nonatomic, retain) UIColor *badgeGradientEndColor; + +/** Specifies the shadow opacity for the badge + + By default is `0.75`. */ +@property (nonatomic) CGFloat badgeShadowOpacity; + +/** Specifies the shadow offset for the badge + + By default is `CGSizeMake(0,2)`. */ +@property (nonatomic) CGSize badgeShadowOffset; + +/** Specifies the font used for the value of the badge + + By default is `[UIFont fontWithName:@"HelveticaNeue-Bold" size:11]`. */ +@property (nonatomic, retain) UIFont *badgeFont; + +/** Specifies the color used for the text in the badge's value + + By default is `[UIColor whiteColor]`. */ +@property (nonatomic, retain) UIColor *badgeTextColor; + +////////////////////////////////////////////////////////////////////////////// +// Internal Methods for Tight coupling with PrettyTabBar +////////////////////////////////////////////////////////////////////////////// + +/** Specifies the title of the button + + By default is `nil`. */ +@property (nonatomic, copy) NSString *title; + +/** Specifies the value of the badge on the button + + By default is `nil`. */ +@property (nonatomic, copy) NSString *badgeValue; + +/** Specifies the image of the button + + By default is `nil`. */ +@property (nonatomic, retain) UIImage *image; + +-(id)initWithTitle:(NSString *)title image:(UIImage *)image tag:(NSInteger)tag; + +@end diff --git a/PrettyKit/PrettyTabBarButton.m b/PrettyKit/PrettyTabBarButton.m new file mode 100644 index 0000000..1744224 --- /dev/null +++ b/PrettyKit/PrettyTabBarButton.m @@ -0,0 +1,357 @@ +// +// PrettyTabBarButton.m +// PrettyExample +// +// Created by Jeremy Foo on 4/5/12. + +// Copyright (c) 2012 Jeremy Foo. (@echoz) +// http://ornyx.net +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of +// this software and associated documentation files (the "Software"), to deal in +// the Software without restriction, including without limitation the rights to +// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +// the Software, and to permit persons to whom the Software is furnished to do so, +// subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#import "PrettyTabBarButton.h" +#import "PrettyDrawing.h" + + +#define IMAGE_HEIGHT 33.0 +#define IMAGE_WIDTH 33.0 + +@interface PrettyTabBarButton (/* Private Method */) +-(CGSize)_sizeForWidth:(CGFloat)width height:(CGFloat)height; +@end + +@implementation PrettyTabBarButton +@synthesize stretchedButton; +@synthesize title = _title, image = _image, badgeValue = _badgeValue; +@synthesize highlightedImage, highlightedImageGradientStartColor, highlightedImageGradientEndColor; +@synthesize textColor, font, highlightedTextColor; +@synthesize highlightImage, highlightGradientStartColor, highlightGradientEndColor, highlightCornerRadius; +@synthesize textShadowOpacity, textShadowOffset; +@synthesize badgeBorderColor, badgeGradientEndColor, badgeGradientStartColor, badgeFont, badgeShadowOffset, badgeShadowOpacity, badgeTextColor; + +- (void) initializeVars +{ + self.contentMode = UIViewContentModeRedraw; + + // default configuration + + self.tag = -1; + + self.title = nil; + self.image = nil; + self.badgeValue = nil; + + self.selected = NO; + + self.opaque = NO; + self.backgroundColor = [UIColor clearColor]; + + self.stretchedButton = NO; + +} + +-(id)initWithTitle:(NSString *)title image:(UIImage *)image tag:(NSInteger)tag { + if ((self = [super init])) { + [self initializeVars]; + + self.tag = tag; + self.title = title; + self.image = image; + + } + return self; +} + +-(id)init { + if ((self = [super init])) { + [self initializeVars]; + } + + return self; +} + +-(id)initWithFrame:(CGRect)frame { + if ((self = [super initWithFrame:frame])) { + [self initializeVars]; + } + return self; +} + +-(id)initWithCoder:(NSCoder *)aDecoder { + if ((self = [super initWithCoder:aDecoder])) { + [self initializeVars]; + } + return self; +} + +-(void)dealloc { + [_title release], _title = nil; + [_image release], _image = nil; + [_badgeValue release], _badgeValue = nil; + + self.highlightedImage = nil; + self.highlightedImageGradientStartColor = nil; + self.highlightedImageGradientEndColor = nil; + + self.font = nil; + self.textColor = nil; + self.highlightedTextColor = nil; + self.badgeBorderColor = nil; + self.badgeGradientStartColor = nil; + self.badgeGradientEndColor = nil; + self.badgeFont = nil; + self.badgeTextColor = nil; + + self.highlightImage = nil; + self.highlightGradientStartColor = nil; + self.highlightGradientEndColor = nil; + + [super dealloc]; +} + + + +#pragma mark - Selection and Accessors + +-(void)setSelected:(BOOL)selected { + [super setSelected:selected]; + [self setNeedsDisplay]; +} + +-(void)setBadgeValue:(NSString *)badgeValue { + if (_badgeValue != badgeValue) { + [_badgeValue release]; + _badgeValue = [badgeValue copy]; + } + + [self setNeedsDisplay]; +} + +#pragma mark - Drawing + +-(CGSize)_sizeForWidth:(CGFloat)width height:(CGFloat)height { + CGFloat returnWidth = IMAGE_WIDTH; + CGFloat returnHeight = IMAGE_HEIGHT; + + if (width < IMAGE_WIDTH) + returnWidth = self.image.size.width; + + if (height < IMAGE_HEIGHT) + returnHeight = self.image.size.height; + + return CGSizeMake(returnWidth, returnHeight); +} + +- (CGSize)drawText:(CGContextRef)context +{ + // draw text + CGContextSaveGState(context); + + if (self.selected) + CGContextSetShadow(context, self.textShadowOffset, self.textShadowOpacity); + + if (self.selected) { + [self.highlightedTextColor setFill]; + } else { + [self.textColor setFill]; + } + + CGSize titleSize = [_title sizeWithFont:self.font constrainedToSize:CGSizeMake(self.frame.size.width, 10.0)]; + [_title drawInRect:CGRectMake((self.frame.size.width - titleSize.width)/2, self.frame.size.height - titleSize.height - 2, titleSize.width, titleSize.height) withFont:self.font]; + + CGContextRestoreGState(context); + return titleSize; +} + +- (void)tintImage:(CGContextRef)context + titleSize:(CGSize)titleSize + imageSize:(CGSize)imageSize + imageRect:(CGRect)imageRect + fromColor:(UIColor *)from + toColor:(UIColor *)to +{ + // draw tint using gradient + CGContextTranslateCTM(context, 0, self.frame.size.height); + CGContextScaleCTM(context, 1.0, -1.0); + + CGRect flippedImageRect = imageRect; + flippedImageRect.origin.y = ((self.frame.size.height - titleSize.height)/2 - (imageSize.height/2)) + titleSize.height; + + CGContextClipToMask(context, flippedImageRect, [self.image CGImage]); + + // because the context has been flipped, the gradient start and end colors also has to be flipped; + [PrettyDrawing drawGradientForContext:context + startPoint:CGPointMake(flippedImageRect.origin.x + flippedImageRect.size.width/2, 0) + endPoint:CGPointMake(flippedImageRect.origin.x + flippedImageRect.size.width/2, flippedImageRect.origin.y + flippedImageRect.size.height) + fromColor:from + toColor:to]; +} + +- (void)drawImage:(CGContextRef)context titleSize:(CGSize)titleSize +{ + // draw image + CGContextSaveGState(context); + + if (self.image) { + + CGSize imageSize = [self _sizeForWidth:self.image.size.width height:self.image.size.height]; + + CGRect imageRect = CGRectMake((self.frame.size.width - imageSize.width)/2, (self.frame.size.height - titleSize.height - imageSize.height)/2, imageSize.width, imageSize.height); + + if (self.selected) { + if (self.highlightedImage) { + CGSize highlightedImageSize = [self _sizeForWidth:self.highlightedImage.size.width height:self.highlightedImage.size.height]; + + [self.highlightedImage drawInRect:CGRectMake((self.frame.size.width - highlightedImageSize.width)/2, (self.frame.size.height - titleSize.height - highlightedImageSize.height)/2, highlightedImageSize.width, highlightedImageSize.height)]; + + } else { + [self tintImage:context + titleSize:titleSize + imageSize:imageSize + imageRect:imageRect + fromColor:self.highlightedImageGradientEndColor + toColor:self.highlightedImageGradientStartColor]; + } + } else { + // draw the image as per normal + [self tintImage:context + titleSize:titleSize + imageSize:imageSize + imageRect:imageRect + fromColor:self.textColor + toColor:self.textColor]; + } + } + + CGContextRestoreGState(context); +} + +- (void)drawBadgeFrame:(CGFloat)badgeHeight badgeFrame:(CGRect)badgeFrame context:(CGContextRef)context +{ + // draw outter border + CGMutablePathRef path = CGPathCreateMutable(); + CGPathAddArc(path, NULL, badgeFrame.origin.x + badgeHeight/2, badgeFrame.origin.y + badgeHeight/2, badgeHeight/2, M_PI / 2, M_PI * 3 / 2, NO); + CGPathAddArc(path, NULL, badgeFrame.origin.x + badgeFrame.size.width - badgeHeight/2, badgeFrame.origin.y + badgeHeight/2, badgeHeight/2, M_PI * 3 / 2, M_PI / 2, NO); + + CGContextSaveGState(context); + + CGContextSetShadow(context, self.badgeShadowOffset, self.badgeShadowOpacity); + CGContextSetFillColorWithColor(context, [self.badgeBorderColor CGColor]); + CGContextAddPath(context, path); + CGContextDrawPath(context, kCGPathFill); + CGPathRelease(path); + + CGContextRestoreGState(context); +} + +- (void)drawInnerBadgeColor:(CGContextRef)context badgeHeight:(CGFloat)badgeHeight badgeFrame:(CGRect)badgeFrame +{ + // draw inner badge color + CGContextSaveGState(context); + + CGMutablePathRef path = CGPathCreateMutable(); + CGPathAddArc(path, NULL, badgeFrame.origin.x + badgeHeight/2, badgeFrame.origin.y + badgeHeight/2, badgeHeight/2 - 2, M_PI / 2, M_PI * 3 / 2, NO); + CGPathAddArc(path, NULL, badgeFrame.origin.x + badgeFrame.size.width - badgeHeight/2, badgeFrame.origin.y + badgeHeight/2, badgeHeight/2 - 2, M_PI * 3 / 2, M_PI / 2, NO); + CGContextAddPath(context, path); + CGPathRelease(path); + + CGContextClip(context); + + CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); + CGFloat locations[] = {0.0, 1.0}; + NSArray *colors = [NSArray arrayWithObjects:(id)[self.badgeGradientStartColor CGColor], (id)[self.badgeGradientEndColor CGColor], nil]; + + CGGradientRef gradient = CGGradientCreateWithColors(colorSpace, (CFArrayRef) colors, locations); + CGContextDrawLinearGradient(context, gradient, CGPointMake(badgeFrame.origin.x + badgeFrame.size.width/2, badgeFrame.origin.y + 0), CGPointMake(badgeFrame.origin.x + badgeFrame.size.width/2, badgeFrame.origin.y + badgeFrame.size.height), 0); + CGGradientRelease(gradient); + CGColorSpaceRelease(colorSpace); + + CGContextRestoreGState(context); +} + +- (void)drawBadgeValue:(CGSize)badgeTextSize badgeFrame:(CGRect)badgeFrame +{ + // draw badgeValue + [self.badgeTextColor setFill]; + [self.badgeValue drawInRect:CGRectMake(badgeFrame.origin.x + (badgeFrame.size.width - badgeTextSize.width)/2, badgeFrame.origin.y + (badgeFrame.size.height - badgeTextSize.height)/2, badgeTextSize.width, badgeTextSize.height) + withFont:self.badgeFont + lineBreakMode:UILineBreakModeTailTruncation]; +} + +- (void)drawBadge:(CGContextRef)context +{ + // draw badge + if (self.badgeValue) { + CGSize badgeTextSize = [self.badgeValue sizeWithFont:self.badgeFont forWidth:(self.frame.size.width * 0.45) lineBreakMode:UILineBreakModeTailTruncation]; + + CGFloat badgeWidth = badgeTextSize.width; + CGFloat badgeHeight = badgeTextSize.height + 4; + + if ((badgeHeight - badgeWidth) < 0) + badgeWidth += badgeHeight * 0.8; + + if (badgeWidth < (badgeHeight)) + badgeWidth = badgeHeight; + + CGRect badgeFrame = CGRectMake((self.frame.size.width - badgeWidth)/2 + 20, 1, badgeWidth, badgeHeight); + + [self drawBadgeFrame:badgeHeight badgeFrame:badgeFrame context:context]; + + [self drawInnerBadgeColor:context badgeHeight:badgeHeight badgeFrame:badgeFrame]; + + [self drawBadgeValue:badgeTextSize badgeFrame:badgeFrame]; + + } +} + +- (void)drawRect:(CGRect)rect +{ + [super drawRect:rect]; + + CGContextRef context = UIGraphicsGetCurrentContext(); + + // draw selection background + if (self.selected) { + if (self.highlightImage) { + [self.highlightImage drawInRect:CGRectMake(2, 1, self.frame.size.width - 2, self.frame.size.height - 1)]; + + } else { + if (self.stretchedButton) { + [PrettyDrawing drawGradient:CGRectMake(0, 0.5, self.frame.size.width, self.frame.size.height) fromColor:self.highlightGradientStartColor toColor:self.highlightGradientEndColor]; + + } else { + [PrettyDrawing drawGradientRoundedRect:CGRectMake(2, 3, self.frame.size.width - 4, self.frame.size.height - 5) + cornerRadius:self.highlightCornerRadius + fromColor:self.highlightGradientStartColor + toColor:self.highlightGradientEndColor]; + + } + } + } + + CGSize titleSize; + titleSize = [self drawText:context]; + + [self drawImage:context titleSize:titleSize]; + + [self drawBadge:context]; + +} + +@end