/libs/FontLabel/FontLabel.m
Objective C | 186 lines | 145 code | 17 blank | 24 comment | 37 complexity | 504ddd4e16404cdc691a2b519e4feab9 MD5 | raw file
Possible License(s): Apache-2.0
1// 2// FontLabel.m 3// FontLabel 4// 5// Created by Kevin Ballard on 5/8/09. 6// Copyright Š 2009 Zynga Game Networks 7// 8// 9// Licensed under the Apache License, Version 2.0 (the "License"); 10// you may not use this file except in compliance with the License. 11// You may obtain a copy of the License at 12// 13// http://www.apache.org/licenses/LICENSE-2.0 14// 15// Unless required by applicable law or agreed to in writing, software 16// distributed under the License is distributed on an "AS IS" BASIS, 17// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18// See the License for the specific language governing permissions and 19// limitations under the License. 20// 21 22#import "FontLabel.h" 23#import "FontManager.h" 24#import "FontLabelStringDrawing.h" 25#import "ZFont.h" 26 27@interface ZFont (ZFontPrivate) 28@property (nonatomic, readonly) CGFloat ratio; 29@end 30 31@implementation FontLabel 32@synthesize zFont; 33@synthesize zAttributedText; 34 35- (id)initWithFrame:(CGRect)frame fontName:(NSString *)fontName pointSize:(CGFloat)pointSize { 36 return [self initWithFrame:frame zFont:[[FontManager sharedManager] zFontWithName:fontName pointSize:pointSize]]; 37} 38 39- (id)initWithFrame:(CGRect)frame zFont:(ZFont *)font { 40 if ((self = [super initWithFrame:frame])) { 41 zFont = [font retain]; 42 } 43 return self; 44} 45 46- (id)initWithFrame:(CGRect)frame font:(CGFontRef)font pointSize:(CGFloat)pointSize { 47 return [self initWithFrame:frame zFont:[ZFont fontWithCGFont:font size:pointSize]]; 48} 49 50- (CGFontRef)cgFont { 51 return self.zFont.cgFont; 52} 53 54- (void)setCGFont:(CGFontRef)font { 55 if (self.zFont.cgFont != font) { 56 self.zFont = [ZFont fontWithCGFont:font size:self.zFont.pointSize]; 57 } 58} 59 60- (CGFloat)pointSize { 61 return self.zFont.pointSize; 62} 63 64- (void)setPointSize:(CGFloat)pointSize { 65 if (self.zFont.pointSize != pointSize) { 66 self.zFont = [ZFont fontWithCGFont:self.zFont.cgFont size:pointSize]; 67 } 68} 69 70- (void)setZAttributedText:(ZAttributedString *)attStr { 71 if (zAttributedText != attStr) { 72 [zAttributedText release]; 73 zAttributedText = [attStr copy]; 74 [self setNeedsDisplay]; 75 } 76} 77 78- (void)drawTextInRect:(CGRect)rect { 79 if (self.zFont == NULL && self.zAttributedText == nil) { 80 [super drawTextInRect:rect]; 81 return; 82 } 83 84 if (self.zAttributedText == nil) { 85 // this method is documented as setting the text color for us, but that doesn't appear to be the case 86 if (self.highlighted) { 87 [(self.highlightedTextColor ?: [UIColor whiteColor]) setFill]; 88 } else { 89 [(self.textColor ?: [UIColor blackColor]) setFill]; 90 } 91 92 ZFont *actualFont = self.zFont; 93 CGSize origSize = rect.size; 94 if (self.numberOfLines == 1) { 95 origSize.height = actualFont.leading; 96 CGPoint point = CGPointMake(rect.origin.x, 97 rect.origin.y + roundf(((rect.size.height - actualFont.leading) / 2.0f))); 98 CGSize size = [self.text sizeWithZFont:actualFont]; 99 if (self.adjustsFontSizeToFitWidth && self.minimumFontSize < actualFont.pointSize) { 100 if (size.width > origSize.width) { 101 CGFloat desiredRatio = (origSize.width * actualFont.ratio) / size.width; 102 CGFloat desiredPointSize = desiredRatio * actualFont.pointSize / actualFont.ratio; 103 actualFont = [actualFont fontWithSize:MAX(MAX(desiredPointSize, self.minimumFontSize), 1.0f)]; 104 size = [self.text sizeWithZFont:actualFont]; 105 } 106 if (!CGSizeEqualToSize(origSize, size)) { 107 switch (self.baselineAdjustment) { 108 case UIBaselineAdjustmentAlignCenters: 109 point.y += roundf((origSize.height - size.height) / 2.0f); 110 break; 111 case UIBaselineAdjustmentAlignBaselines: 112 point.y += (self.zFont.ascender - actualFont.ascender); 113 break; 114 case UIBaselineAdjustmentNone: 115 break; 116 } 117 } 118 } 119 size.width = MIN(size.width, origSize.width); 120 // adjust the point for alignment 121 switch (self.textAlignment) { 122 case UITextAlignmentLeft: 123 break; 124 case UITextAlignmentCenter: 125 point.x += (origSize.width - size.width) / 2.0f; 126 break; 127 case UITextAlignmentRight: 128 point.x += origSize.width - size.width; 129 break; 130 } 131 [self.text drawAtPoint:point forWidth:size.width withZFont:actualFont lineBreakMode:self.lineBreakMode]; 132 } else { 133 CGSize size = [self.text sizeWithZFont:actualFont constrainedToSize:origSize lineBreakMode:self.lineBreakMode numberOfLines:self.numberOfLines]; 134 CGPoint point = rect.origin; 135 point.y += roundf((rect.size.height - size.height) / 2.0f); 136 rect = (CGRect){point, CGSizeMake(rect.size.width, size.height)}; 137 [self.text drawInRect:rect withZFont:actualFont lineBreakMode:self.lineBreakMode alignment:self.textAlignment numberOfLines:self.numberOfLines]; 138 } 139 } else { 140 ZAttributedString *attStr = self.zAttributedText; 141 if (self.highlighted) { 142 // modify the string to change the base color 143 ZMutableAttributedString *mutStr = [[attStr mutableCopy] autorelease]; 144 NSRange activeRange = NSMakeRange(0, attStr.length); 145 while (activeRange.length > 0) { 146 NSRange effective; 147 UIColor *color = [attStr attribute:ZForegroundColorAttributeName atIndex:activeRange.location 148 longestEffectiveRange:&effective inRange:activeRange]; 149 if (color == nil) { 150 [mutStr addAttribute:ZForegroundColorAttributeName value:[UIColor whiteColor] range:effective]; 151 } 152 activeRange.location += effective.length, activeRange.length -= effective.length; 153 } 154 attStr = mutStr; 155 } 156 CGSize size = [attStr sizeConstrainedToSize:rect.size lineBreakMode:self.lineBreakMode numberOfLines:self.numberOfLines]; 157 CGPoint point = rect.origin; 158 point.y += roundf((rect.size.height - size.height) / 2.0f); 159 rect = (CGRect){point, CGSizeMake(rect.size.width, size.height)}; 160 [attStr drawInRect:rect withLineBreakMode:self.lineBreakMode alignment:self.textAlignment numberOfLines:self.numberOfLines]; 161 } 162} 163 164- (CGRect)textRectForBounds:(CGRect)bounds limitedToNumberOfLines:(NSInteger)numberOfLines { 165 if (self.zFont == NULL && self.zAttributedText == nil) { 166 return [super textRectForBounds:bounds limitedToNumberOfLines:numberOfLines]; 167 } 168 169 if (numberOfLines == 1) { 170 // if numberOfLines == 1 we need to use the version that converts spaces 171 CGSize size = [self.text sizeWithZFont:self.zFont]; 172 bounds.size.width = MIN(bounds.size.width, size.width); 173 bounds.size.height = MIN(bounds.size.height, size.height); 174 } else { 175 if (numberOfLines > 0) bounds.size.height = MIN(bounds.size.height, self.zFont.leading * numberOfLines); 176 bounds.size = [self.text sizeWithZFont:self.zFont constrainedToSize:bounds.size lineBreakMode:self.lineBreakMode]; 177 } 178 return bounds; 179} 180 181- (void)dealloc { 182 [zFont release]; 183 [zAttributedText release]; 184 [super dealloc]; 185} 186@end