diff options
-rw-r--r-- | GTMiPhone.xcodeproj/project.pbxproj | 30 | ||||
-rwxr-xr-x | iPhone/GTMFadeTruncatingLabel.h | 32 | ||||
-rwxr-xr-x | iPhone/GTMFadeTruncatingLabel.m | 115 | ||||
-rw-r--r-- | iPhone/GTMFadeTruncatingLabelTest.m | 67 | ||||
-rw-r--r-- | iPhone/TestData/GTMFadeTruncatingLabelTest1.png | bin | 0 -> 2788 bytes | |||
-rw-r--r-- | iPhone/TestData/GTMFadeTruncatingLabelTest2.png | bin | 0 -> 1569 bytes | |||
-rw-r--r-- | iPhone/TestData/GTMFadeTruncatingLabelTest3.png | bin | 0 -> 3289 bytes | |||
-rw-r--r-- | iPhone/TestData/GTMFadeTruncatingLabelTest4.png | bin | 0 -> 1919 bytes | |||
-rw-r--r-- | iPhone/TestData/GTMFadeTruncatingLabelTest5.png | bin | 0 -> 2665 bytes |
9 files changed, 244 insertions, 0 deletions
diff --git a/GTMiPhone.xcodeproj/project.pbxproj b/GTMiPhone.xcodeproj/project.pbxproj index a91a4a9..9a88a9b 100644 --- a/GTMiPhone.xcodeproj/project.pbxproj +++ b/GTMiPhone.xcodeproj/project.pbxproj @@ -107,6 +107,13 @@ 8BFE15C80FB0F764001BE894 /* GTMABAddressBookTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 8BFE15C30FB0F764001BE894 /* GTMABAddressBookTest.m */; }; 8BFE15C90FB0F764001BE894 /* phone.png in Resources */ = {isa = PBXBuildFile; fileRef = 8BFE15C50FB0F764001BE894 /* phone.png */; }; 8BFFCD7811C1934900E45777 /* GTMNSObject+KeyValueObservingTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 8B6C18730F3769D200E51E5D /* GTMNSObject+KeyValueObservingTest.m */; }; + 9340CF9F140550CE0026DDC9 /* GTMFadeTruncatingLabel.m in Sources */ = {isa = PBXBuildFile; fileRef = 9340CF9D140550CE0026DDC9 /* GTMFadeTruncatingLabel.m */; }; + 9340CFA0140550CE0026DDC9 /* GTMFadeTruncatingLabelTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 9340CF9E140550CE0026DDC9 /* GTMFadeTruncatingLabelTest.m */; }; + 9340CFA6140550E30026DDC9 /* GTMFadeTruncatingLabelTest1.png in Resources */ = {isa = PBXBuildFile; fileRef = 9340CFA1140550E30026DDC9 /* GTMFadeTruncatingLabelTest1.png */; }; + 9340CFA7140550E30026DDC9 /* GTMFadeTruncatingLabelTest2.png in Resources */ = {isa = PBXBuildFile; fileRef = 9340CFA2140550E30026DDC9 /* GTMFadeTruncatingLabelTest2.png */; }; + 9340CFA8140550E30026DDC9 /* GTMFadeTruncatingLabelTest3.png in Resources */ = {isa = PBXBuildFile; fileRef = 9340CFA3140550E30026DDC9 /* GTMFadeTruncatingLabelTest3.png */; }; + 9340CFA9140550E30026DDC9 /* GTMFadeTruncatingLabelTest4.png in Resources */ = {isa = PBXBuildFile; fileRef = 9340CFA4140550E30026DDC9 /* GTMFadeTruncatingLabelTest4.png */; }; + 9340CFAA140550E30026DDC9 /* GTMFadeTruncatingLabelTest5.png in Resources */ = {isa = PBXBuildFile; fileRef = 9340CFA5140550E30026DDC9 /* GTMFadeTruncatingLabelTest5.png */; }; F417115A0ECDFF0400B9B276 /* GTMLightweightProxy.m in Sources */ = {isa = PBXBuildFile; fileRef = F41711580ECDFF0400B9B276 /* GTMLightweightProxy.m */; }; F417115B0ECDFF0400B9B276 /* GTMLightweightProxyTest.m in Sources */ = {isa = PBXBuildFile; fileRef = F41711590ECDFF0400B9B276 /* GTMLightweightProxyTest.m */; }; F418AF990E7558EC004FB565 /* GTMExceptionalInlines.m in Sources */ = {isa = PBXBuildFile; fileRef = F418AF940E7558DC004FB565 /* GTMExceptionalInlines.m */; }; @@ -274,6 +281,14 @@ 8BFE15C20FB0F764001BE894 /* GTMABAddressBook.strings */ = {isa = PBXFileReference; fileEncoding = 10; lastKnownFileType = text.plist.strings; path = GTMABAddressBook.strings; sourceTree = "<group>"; }; 8BFE15C30FB0F764001BE894 /* GTMABAddressBookTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GTMABAddressBookTest.m; sourceTree = "<group>"; }; 8BFE15C50FB0F764001BE894 /* phone.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = phone.png; sourceTree = "<group>"; }; + 9340CF9C140550CE0026DDC9 /* GTMFadeTruncatingLabel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GTMFadeTruncatingLabel.h; sourceTree = "<group>"; }; + 9340CF9D140550CE0026DDC9 /* GTMFadeTruncatingLabel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GTMFadeTruncatingLabel.m; sourceTree = "<group>"; }; + 9340CF9E140550CE0026DDC9 /* GTMFadeTruncatingLabelTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GTMFadeTruncatingLabelTest.m; sourceTree = "<group>"; }; + 9340CFA1140550E30026DDC9 /* GTMFadeTruncatingLabelTest1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = GTMFadeTruncatingLabelTest1.png; path = TestData/GTMFadeTruncatingLabelTest1.png; sourceTree = "<group>"; }; + 9340CFA2140550E30026DDC9 /* GTMFadeTruncatingLabelTest2.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = GTMFadeTruncatingLabelTest2.png; path = TestData/GTMFadeTruncatingLabelTest2.png; sourceTree = "<group>"; }; + 9340CFA3140550E30026DDC9 /* GTMFadeTruncatingLabelTest3.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = GTMFadeTruncatingLabelTest3.png; path = TestData/GTMFadeTruncatingLabelTest3.png; sourceTree = "<group>"; }; + 9340CFA4140550E30026DDC9 /* GTMFadeTruncatingLabelTest4.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = GTMFadeTruncatingLabelTest4.png; path = TestData/GTMFadeTruncatingLabelTest4.png; sourceTree = "<group>"; }; + 9340CFA5140550E30026DDC9 /* GTMFadeTruncatingLabelTest5.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = GTMFadeTruncatingLabelTest5.png; path = TestData/GTMFadeTruncatingLabelTest5.png; sourceTree = "<group>"; }; CAD23A741174AE7800EA94E5 /* DebugiPhone32.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = DebugiPhone32.xcconfig; sourceTree = "<group>"; }; CAD23A751174AE7800EA94E5 /* DebugiPhone313.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = DebugiPhone313.xcconfig; sourceTree = "<group>"; }; CAD23A761174AE7800EA94E5 /* ReleaseiPhone32.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = ReleaseiPhone32.xcconfig; sourceTree = "<group>"; }; @@ -387,6 +402,11 @@ 64D0F5CB0FD3E66A00506CC7 /* TestData */ = { isa = PBXGroup; children = ( + 9340CFA1140550E30026DDC9 /* GTMFadeTruncatingLabelTest1.png */, + 9340CFA2140550E30026DDC9 /* GTMFadeTruncatingLabelTest2.png */, + 9340CFA3140550E30026DDC9 /* GTMFadeTruncatingLabelTest3.png */, + 9340CFA4140550E30026DDC9 /* GTMFadeTruncatingLabelTest4.png */, + 9340CFA5140550E30026DDC9 /* GTMFadeTruncatingLabelTest5.png */, 64D0F5CC0FD3E68400506CC7 /* GTMUIImage+Resize_100x100_to_60x40.png */, 64D0F5CD0FD3E68400506CC7 /* GTMUIImage+Resize_50x100.png */, 448D61B011AC1AAD0097ACBC /* GTMUIImage+Resize_50x100_flipped.png */, @@ -414,6 +434,9 @@ 8BA5F4060E75669000798036 /* iPhone */ = { isa = PBXGroup; children = ( + 9340CF9C140550CE0026DDC9 /* GTMFadeTruncatingLabel.h */, + 9340CF9D140550CE0026DDC9 /* GTMFadeTruncatingLabel.m */, + 9340CF9E140550CE0026DDC9 /* GTMFadeTruncatingLabelTest.m */, F4E3B3D60EB5EF2400CB713D /* GTMUIFont+LineHeight.h */, F4E3B3D70EB5EF2400CB713D /* GTMUIFont+LineHeight.m */, F4E3B3E10EB5EF9A00CB713D /* GTMUIFont+LineHeightTest.m */, @@ -752,6 +775,11 @@ 64D0F5ED0FD3E68400506CC7 /* GTMUIImage+Resize_100x100.png in Resources */, 64D0F5EE0FD3E68400506CC7 /* GTMUIImage+Resize_100x100_to_40x60.png in Resources */, 64D0F5EF0FD3E68400506CC7 /* GTMUIImage+Resize_100x100_to_50x50.png in Resources */, + 9340CFA6140550E30026DDC9 /* GTMFadeTruncatingLabelTest1.png in Resources */, + 9340CFA7140550E30026DDC9 /* GTMFadeTruncatingLabelTest2.png in Resources */, + 9340CFA8140550E30026DDC9 /* GTMFadeTruncatingLabelTest3.png in Resources */, + 9340CFA9140550E30026DDC9 /* GTMFadeTruncatingLabelTest4.png in Resources */, + 9340CFAA140550E30026DDC9 /* GTMFadeTruncatingLabelTest5.png in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -852,6 +880,8 @@ 8B2908B211F8E7070064F50F /* GTMNSFileHandle+UniqueName.m in Sources */, 8B2908B311F8E7070064F50F /* GTMNSFileHandle+UniqueNameTest.m in Sources */, F4746721129703600022C1FB /* GTMSenTestCaseTest.m in Sources */, + 9340CF9F140550CE0026DDC9 /* GTMFadeTruncatingLabel.m in Sources */, + 9340CFA0140550CE0026DDC9 /* GTMFadeTruncatingLabelTest.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/iPhone/GTMFadeTruncatingLabel.h b/iPhone/GTMFadeTruncatingLabel.h new file mode 100755 index 0000000..5b768f0 --- /dev/null +++ b/iPhone/GTMFadeTruncatingLabel.h @@ -0,0 +1,32 @@ +// +// GTMFadeTruncatingLabel.h +// +// Copyright 2011 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may not +// use this file except in compliance with the License. You may obtain a copy +// of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations under +// the License. +// + +#import <UIKit/UIKit.h> + +typedef enum { + GTMFadeTruncatingTail = 0x1, + GTMFadeTruncatingHead = 0x2, + GTMFadeTruncatingHeadAndTail = GTMFadeTruncatingHead | GTMFadeTruncatingTail +} GTMFadeTruncatingMode; + +@interface GTMFadeTruncatingLabel : UILabel + +// Which side(s) to truncate. +@property(nonatomic, assign) GTMFadeTruncatingMode truncateMode; + +@end diff --git a/iPhone/GTMFadeTruncatingLabel.m b/iPhone/GTMFadeTruncatingLabel.m new file mode 100755 index 0000000..619e7bb --- /dev/null +++ b/iPhone/GTMFadeTruncatingLabel.m @@ -0,0 +1,115 @@ +// +// GTMFadeTruncatingLabel.m +// +// Copyright 2011 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may not +// use this file except in compliance with the License. You may obtain a copy +// of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations under +// the License. +// +#import "GTMFadeTruncatingLabel.h" + +@interface GTMFadeTruncatingLabel () +- (void)setup; +- (UIImage*)getLinearGradient:(CGRect)rect; +@end + +@implementation GTMFadeTruncatingLabel + +@synthesize truncateMode = truncateMode_; + +- (void)setup { + self.backgroundColor = [UIColor clearColor]; + truncateMode_ = GTMFadeTruncatingTail; +} + +- (id)initWithFrame:(CGRect)frame { + self = [super initWithFrame:frame]; + if (self) { + [self setup]; + } + return self; +} + +- (void)awakeFromNib { + [self setup]; +} + +// Draw fade gradient mask if text is wider than rect. +- (void)drawTextInRect:(CGRect)requestedRect { + CGContextRef context = UIGraphicsGetCurrentContext(); + CGContextSaveGState(context); + + CGSize size = [self.text sizeWithFont:self.font]; + if (size.width > requestedRect.size.width) { + UIImage* image = [self getLinearGradient:requestedRect]; + CGContextClipToMask(context, self.bounds, image.CGImage); + } + + CGContextSetFillColorWithColor(context, self.textColor.CGColor); + [self.text drawInRect:requestedRect + withFont:self.font + lineBreakMode:UILineBreakModeClip + alignment:self.textAlignment]; + + CGContextRestoreGState(context); +} + +// Create gradient opacity mask based on direction. +- (UIImage*)getLinearGradient:(CGRect)rect { + // Create an opaque context. + CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceGray(); + CGContextRef context = CGBitmapContextCreate (NULL, + rect.size.width, + rect.size.height, + 8, + 4*rect.size.width, + colorSpace, + kCGImageAlphaNone); + + // White background will mask opaque, black gradient will mask transparent. + CGContextSetFillColorWithColor(context, [UIColor whiteColor].CGColor); + CGContextFillRect(context, rect); + + // Create gradient from white to black. + CGFloat locs[2] = { 0.0f, 1.0f }; + CGFloat components[4] = { 1.0f, 1.0f, 0.0f, 1.0f }; + CGGradientRef gradient = + CGGradientCreateWithColorComponents(colorSpace, components, locs, 2); + CGColorSpaceRelease(colorSpace); + + // Draw head and/or tail gradient. + CGFloat fadeWidth = MIN(rect.size.height * 2, floor(rect.size.width / 4)); + CGFloat minX = CGRectGetMinX(rect); + CGFloat maxX = CGRectGetMaxX(rect); + if (self.truncateMode & GTMFadeTruncatingTail) { + CGFloat startX = maxX - fadeWidth; + CGPoint startPoint = CGPointMake(startX, CGRectGetMidY(rect)); + CGPoint endPoint = CGPointMake(maxX, CGRectGetMidY(rect)); + CGContextDrawLinearGradient(context, gradient, startPoint, endPoint, 0); + } + if (self.truncateMode & GTMFadeTruncatingHead) { + CGFloat startX = minX + fadeWidth; + CGPoint startPoint = CGPointMake(startX, CGRectGetMidY(rect)); + CGPoint endPoint = CGPointMake(minX, CGRectGetMidY(rect)); + CGContextDrawLinearGradient(context, gradient, startPoint, endPoint, 0); + } + CGGradientRelease(gradient); + + // Clean up, return image. + CGImageRef ref = CGBitmapContextCreateImage(context); + UIImage* image = [UIImage imageWithCGImage:ref]; + CGImageRelease(ref); + CGContextRelease(context); + return image; +} + +@end diff --git a/iPhone/GTMFadeTruncatingLabelTest.m b/iPhone/GTMFadeTruncatingLabelTest.m new file mode 100644 index 0000000..052a32f --- /dev/null +++ b/iPhone/GTMFadeTruncatingLabelTest.m @@ -0,0 +1,67 @@ +// +// GTMFadeTruncatingLabelTest.m +// +// Copyright 2011 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may not +// use this file except in compliance with the License. You may obtain a copy +// of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations under +// the License. +// +#import "GTMNSObject+UnitTesting.h" +#import "GTMSenTestCase.h" +#import "GTMFadeTruncatingLabel.h" + +@interface GTMFadeTruncatingLabelTest : GTMTestCase +@end + + +@implementation GTMFadeTruncatingLabelTest + +- (void)testFadeTruncatingLabelRight { + GTMFadeTruncatingLabel* label = [[[GTMFadeTruncatingLabel alloc] + initWithFrame:CGRectMake(0, 0, 200, 25)] + autorelease]; + label.text = @"A very long string that won't fit"; + GTMAssertObjectImageEqualToImageNamed(label, + @"GTMFadeTruncatingLabelTest1", + @"Mismatched image."); + label.text = @"A short string"; + GTMAssertObjectImageEqualToImageNamed(label, + @"GTMFadeTruncatingLabelTest2", + @"Mismatched image."); + + // Dark background, light text. + label.backgroundColor = [UIColor blackColor]; + [label setTextColor:[UIColor whiteColor]]; + + label.text = @"A very long string that won't fit"; + GTMAssertObjectImageEqualToImageNamed(label, + @"GTMFadeTruncatingLabelTest3", + @"Mismatched image."); + label.text = @"A short string"; + GTMAssertObjectImageEqualToImageNamed(label, + @"GTMFadeTruncatingLabelTest4", + @"Mismatched image."); +} + +- (void)testFadeTruncatingLabelLeftAndRight { + GTMFadeTruncatingLabel* label = [[[GTMFadeTruncatingLabel alloc] + initWithFrame:CGRectMake(0, 0, 200, 25)] + autorelease]; + label.truncateMode = GTMFadeTruncatingHeadAndTail; + + label.text = @"Fade on both left and right"; + GTMAssertObjectImageEqualToImageNamed(label, + @"GTMFadeTruncatingLabelTest5", + @"Mismatched image."); +} + +@end diff --git a/iPhone/TestData/GTMFadeTruncatingLabelTest1.png b/iPhone/TestData/GTMFadeTruncatingLabelTest1.png Binary files differnew file mode 100644 index 0000000..d5d7910 --- /dev/null +++ b/iPhone/TestData/GTMFadeTruncatingLabelTest1.png diff --git a/iPhone/TestData/GTMFadeTruncatingLabelTest2.png b/iPhone/TestData/GTMFadeTruncatingLabelTest2.png Binary files differnew file mode 100644 index 0000000..80d95fd --- /dev/null +++ b/iPhone/TestData/GTMFadeTruncatingLabelTest2.png diff --git a/iPhone/TestData/GTMFadeTruncatingLabelTest3.png b/iPhone/TestData/GTMFadeTruncatingLabelTest3.png Binary files differnew file mode 100644 index 0000000..eba21b2 --- /dev/null +++ b/iPhone/TestData/GTMFadeTruncatingLabelTest3.png diff --git a/iPhone/TestData/GTMFadeTruncatingLabelTest4.png b/iPhone/TestData/GTMFadeTruncatingLabelTest4.png Binary files differnew file mode 100644 index 0000000..e9f59c8 --- /dev/null +++ b/iPhone/TestData/GTMFadeTruncatingLabelTest4.png diff --git a/iPhone/TestData/GTMFadeTruncatingLabelTest5.png b/iPhone/TestData/GTMFadeTruncatingLabelTest5.png Binary files differnew file mode 100644 index 0000000..ba378d2 --- /dev/null +++ b/iPhone/TestData/GTMFadeTruncatingLabelTest5.png |