/libs/FontLabel/FontLabel.m

http://github.com/kstenerud/ObjectAL-for-iPhone · Objective C · 186 lines · 145 code · 17 blank · 24 comment · 37 complexity · 504ddd4e16404cdc691a2b519e4feab9 MD5 · raw file

  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. #import "FontLabel.h"
  22. #import "FontManager.h"
  23. #import "FontLabelStringDrawing.h"
  24. #import "ZFont.h"
  25. @interface ZFont (ZFontPrivate)
  26. @property (nonatomic, readonly) CGFloat ratio;
  27. @end
  28. @implementation FontLabel
  29. @synthesize zFont;
  30. @synthesize zAttributedText;
  31. - (id)initWithFrame:(CGRect)frame fontName:(NSString *)fontName pointSize:(CGFloat)pointSize {
  32. return [self initWithFrame:frame zFont:[[FontManager sharedManager] zFontWithName:fontName pointSize:pointSize]];
  33. }
  34. - (id)initWithFrame:(CGRect)frame zFont:(ZFont *)font {
  35. if ((self = [super initWithFrame:frame])) {
  36. zFont = [font retain];
  37. }
  38. return self;
  39. }
  40. - (id)initWithFrame:(CGRect)frame font:(CGFontRef)font pointSize:(CGFloat)pointSize {
  41. return [self initWithFrame:frame zFont:[ZFont fontWithCGFont:font size:pointSize]];
  42. }
  43. - (CGFontRef)cgFont {
  44. return self.zFont.cgFont;
  45. }
  46. - (void)setCGFont:(CGFontRef)font {
  47. if (self.zFont.cgFont != font) {
  48. self.zFont = [ZFont fontWithCGFont:font size:self.zFont.pointSize];
  49. }
  50. }
  51. - (CGFloat)pointSize {
  52. return self.zFont.pointSize;
  53. }
  54. - (void)setPointSize:(CGFloat)pointSize {
  55. if (self.zFont.pointSize != pointSize) {
  56. self.zFont = [ZFont fontWithCGFont:self.zFont.cgFont size:pointSize];
  57. }
  58. }
  59. - (void)setZAttributedText:(ZAttributedString *)attStr {
  60. if (zAttributedText != attStr) {
  61. [zAttributedText release];
  62. zAttributedText = [attStr copy];
  63. [self setNeedsDisplay];
  64. }
  65. }
  66. - (void)drawTextInRect:(CGRect)rect {
  67. if (self.zFont == NULL && self.zAttributedText == nil) {
  68. [super drawTextInRect:rect];
  69. return;
  70. }
  71. if (self.zAttributedText == nil) {
  72. // this method is documented as setting the text color for us, but that doesn't appear to be the case
  73. if (self.highlighted) {
  74. [(self.highlightedTextColor ?: [UIColor whiteColor]) setFill];
  75. } else {
  76. [(self.textColor ?: [UIColor blackColor]) setFill];
  77. }
  78. ZFont *actualFont = self.zFont;
  79. CGSize origSize = rect.size;
  80. if (self.numberOfLines == 1) {
  81. origSize.height = actualFont.leading;
  82. CGPoint point = CGPointMake(rect.origin.x,
  83. rect.origin.y + roundf(((rect.size.height - actualFont.leading) / 2.0f)));
  84. CGSize size = [self.text sizeWithZFont:actualFont];
  85. if (self.adjustsFontSizeToFitWidth && self.minimumFontSize < actualFont.pointSize) {
  86. if (size.width > origSize.width) {
  87. CGFloat desiredRatio = (origSize.width * actualFont.ratio) / size.width;
  88. CGFloat desiredPointSize = desiredRatio * actualFont.pointSize / actualFont.ratio;
  89. actualFont = [actualFont fontWithSize:MAX(MAX(desiredPointSize, self.minimumFontSize), 1.0f)];
  90. size = [self.text sizeWithZFont:actualFont];
  91. }
  92. if (!CGSizeEqualToSize(origSize, size)) {
  93. switch (self.baselineAdjustment) {
  94. case UIBaselineAdjustmentAlignCenters:
  95. point.y += roundf((origSize.height - size.height) / 2.0f);
  96. break;
  97. case UIBaselineAdjustmentAlignBaselines:
  98. point.y += (self.zFont.ascender - actualFont.ascender);
  99. break;
  100. case UIBaselineAdjustmentNone:
  101. break;
  102. }
  103. }
  104. }
  105. size.width = MIN(size.width, origSize.width);
  106. // adjust the point for alignment
  107. switch (self.textAlignment) {
  108. case UITextAlignmentLeft:
  109. break;
  110. case UITextAlignmentCenter:
  111. point.x += (origSize.width - size.width) / 2.0f;
  112. break;
  113. case UITextAlignmentRight:
  114. point.x += origSize.width - size.width;
  115. break;
  116. }
  117. [self.text drawAtPoint:point forWidth:size.width withZFont:actualFont lineBreakMode:self.lineBreakMode];
  118. } else {
  119. CGSize size = [self.text sizeWithZFont:actualFont constrainedToSize:origSize lineBreakMode:self.lineBreakMode numberOfLines:self.numberOfLines];
  120. CGPoint point = rect.origin;
  121. point.y += roundf((rect.size.height - size.height) / 2.0f);
  122. rect = (CGRect){point, CGSizeMake(rect.size.width, size.height)};
  123. [self.text drawInRect:rect withZFont:actualFont lineBreakMode:self.lineBreakMode alignment:self.textAlignment numberOfLines:self.numberOfLines];
  124. }
  125. } else {
  126. ZAttributedString *attStr = self.zAttributedText;
  127. if (self.highlighted) {
  128. // modify the string to change the base color
  129. ZMutableAttributedString *mutStr = [[attStr mutableCopy] autorelease];
  130. NSRange activeRange = NSMakeRange(0, attStr.length);
  131. while (activeRange.length > 0) {
  132. NSRange effective;
  133. UIColor *color = [attStr attribute:ZForegroundColorAttributeName atIndex:activeRange.location
  134. longestEffectiveRange:&effective inRange:activeRange];
  135. if (color == nil) {
  136. [mutStr addAttribute:ZForegroundColorAttributeName value:[UIColor whiteColor] range:effective];
  137. }
  138. activeRange.location += effective.length, activeRange.length -= effective.length;
  139. }
  140. attStr = mutStr;
  141. }
  142. CGSize size = [attStr sizeConstrainedToSize:rect.size lineBreakMode:self.lineBreakMode numberOfLines:self.numberOfLines];
  143. CGPoint point = rect.origin;
  144. point.y += roundf((rect.size.height - size.height) / 2.0f);
  145. rect = (CGRect){point, CGSizeMake(rect.size.width, size.height)};
  146. [attStr drawInRect:rect withLineBreakMode:self.lineBreakMode alignment:self.textAlignment numberOfLines:self.numberOfLines];
  147. }
  148. }
  149. - (CGRect)textRectForBounds:(CGRect)bounds limitedToNumberOfLines:(NSInteger)numberOfLines {
  150. if (self.zFont == NULL && self.zAttributedText == nil) {
  151. return [super textRectForBounds:bounds limitedToNumberOfLines:numberOfLines];
  152. }
  153. if (numberOfLines == 1) {
  154. // if numberOfLines == 1 we need to use the version that converts spaces
  155. CGSize size = [self.text sizeWithZFont:self.zFont];
  156. bounds.size.width = MIN(bounds.size.width, size.width);
  157. bounds.size.height = MIN(bounds.size.height, size.height);
  158. } else {
  159. if (numberOfLines > 0) bounds.size.height = MIN(bounds.size.height, self.zFont.leading * numberOfLines);
  160. bounds.size = [self.text sizeWithZFont:self.zFont constrainedToSize:bounds.size lineBreakMode:self.lineBreakMode];
  161. }
  162. return bounds;
  163. }
  164. - (void)dealloc {
  165. [zFont release];
  166. [zAttributedText release];
  167. [super dealloc];
  168. }
  169. @end