diff --git a/samples/TTCatalog/Classes/StyleTestController.m b/samples/TTCatalog/Classes/StyleTestController.m index 60b7f28193..eb646888be 100644 --- a/samples/TTCatalog/Classes/StyleTestController.m +++ b/samples/TTCatalog/Classes/StyleTestController.m @@ -36,7 +36,21 @@ - (void)loadView { [TTRoundedRectangleShape shapeWithTopLeft:0 topRight:0 bottomRight:10 bottomLeft:10] next: [TTSolidFillStyle styleWithColor:[UIColor whiteColor] next: [TTSolidBorderStyle styleWithColor:black width:1 next:nil]]], - + + // SpeechBubble + [TTShapeStyle styleWithShape:[TTSpeechBubbleShape shapeWithRadius:5 pointLocation:60 + pointAngle:90 + pointSize:CGSizeMake(20,10)] next: + [TTSolidFillStyle styleWithColor:[UIColor whiteColor] next: + [TTSolidBorderStyle styleWithColor:black width:1 next:nil]]], + + // SpeechBubble + [TTShapeStyle styleWithShape:[TTSpeechBubbleShape shapeWithRadius:5 pointLocation:290 + pointAngle:270 + pointSize:CGSizeMake(20,10)] next: + [TTSolidFillStyle styleWithColor:[UIColor whiteColor] next: + [TTSolidBorderStyle styleWithColor:black width:1 next:nil]]], + // Drop shadow [TTShapeStyle styleWithShape:[TTRoundedRectangleShape shapeWithRadius:10] next: [TTShadowStyle styleWithColor:RGBACOLOR(0,0,0,0.5) blur:5 offset:CGSizeMake(2, 2) next: @@ -98,6 +112,7 @@ - (void)loadView { [TTMaskStyle styleWithMask:TTIMAGE(@"bundle://mask.png") next: [TTLinearGradientFillStyle styleWithColor1:RGBCOLOR(0, 180, 231) color2:RGBCOLOR(0, 0, 255) next:nil]], + nil]; CGFloat padding = 10; diff --git a/samples/TTCatalog/Classes/StyledTextTableTestController.m b/samples/TTCatalog/Classes/StyledTextTableTestController.m index 7b29fe9b10..de0a86f0c7 100644 --- a/samples/TTCatalog/Classes/StyledTextTableTestController.m +++ b/samples/TTCatalog/Classes/StyledTextTableTestController.m @@ -1,34 +1,7 @@ #import "StyledTextTableTestController.h" -@interface TextTableTestStyleSheet : TTDefaultStyleSheet -@end - -@implementation TextTableTestStyleSheet - -- (TTStyle*)block { - return [TTBoxStyle styleWithMargin:UIEdgeInsetsMake(5,10,5,10) next:nil]; -} - -@end - @implementation StyledTextTableTestController - -/////////////////////////////////////////////////////////////////////////////////////////////////// -// NSObject - -- (id)init { - if (self = [super init]) { - [TTStyleSheet setGlobalStyleSheet:[[[TextTableTestStyleSheet alloc] init] autorelease]]; - } - return self; -} - -- (void)dealloc { - [TTStyleSheet setGlobalStyleSheet:nil]; - [super dealloc]; -} - /////////////////////////////////////////////////////////////////////////////////////////////////// // UIViewController @@ -50,14 +23,14 @@ - (void)loadView { - (id)createDataSource { NSArray* strings = [NSArray arrayWithObjects: - [TTStyledText textFromXHTML:@"

This is a whole bunch of text made from \ -characters and followed by this url http://bit.ly/1234

"], - [TTStyledText textFromXHTML:@"

Here we have a url http://www.h0tlinkz.com \ -followed by another http://www.internets.com

"], - [TTStyledText textFromXHTML:@"

http://www.cnn.com is a url and the words you \ -are now reading are the text that follows

"], - [TTStyledText textFromXHTML:@"

Here is text that has absolutely no styles. \ -Move along now. Nothing to see here. Goodbye now.

"], + [TTStyledText textFromXHTML:@"This is a whole bunch of text made from \ +characters and followed by this url http://bit.ly/1234"], + [TTStyledText textFromXHTML:@"Here we have a url http://www.h0tlinkz.com \ +followed by another http://www.internets.com"], + [TTStyledText textFromXHTML:@"http://www.cnn.com is a url and the words you \ +are now reading are the text that follows"], + [TTStyledText textFromXHTML:@"Here is text that has absolutely no styles. \ +Move along now. Nothing to see here. Goodbye now."], // @"Let's test out some line breaks.\n\nOh yeah.", // @"This is a message with a long url in it http://www.foo.com/abra/cadabra/abrabra/dabarababa", nil]; diff --git a/src/TTGlobal.m b/src/TTGlobal.m index 474794474e..21aa69a6b7 100644 --- a/src/TTGlobal.m +++ b/src/TTGlobal.m @@ -104,11 +104,19 @@ void TTNetworkRequestStopped() { } BOOL TTIsBundleURL(NSString* url) { - return [url rangeOfString:@"bundle://" options:0 range:NSMakeRange(0,9)].location == 0; + if (url.length >= 9) { + return [url rangeOfString:@"bundle://" options:0 range:NSMakeRange(0,9)].location == 0; + } else { + return NO; + } } BOOL TTIsDocumentsURL(NSString* url) { - return [url rangeOfString:@"documents://" options:0 range:NSMakeRange(0,12)].location == 0; + if (url.length >= 12) { + return [url rangeOfString:@"documents://" options:0 range:NSMakeRange(0,12)].location == 0; + } else { + return NO; + } } NSString* TTPathForBundleResource(NSString* relativePath) { diff --git a/src/TTShape.m b/src/TTShape.m index 7664354c85..6a84566d26 100644 --- a/src/TTShape.m +++ b/src/TTShape.m @@ -7,6 +7,7 @@ static const CGFloat kArrowPointWidth = 2.8; static const CGFloat kArrowRadius = 2; +static CGFloat kInsetWidth = 5; #define RD(_RADIUS) (_RADIUS == TT_ROUNDED ? round(fh/2) : _RADIUS) @@ -503,3 +504,226 @@ - (UIEdgeInsets)insetsForSize:(CGSize)size { } @end + +/////////////////////////////////////////////////////////////////////////////////////////////////// + +@implementation TTSpeechBubbleShape + +@synthesize radius = _radius, pointLocation = _pointLocation, pointAngle = _pointAngle, + pointSize = _pointSize; + +/////////////////////////////////////////////////////////////////////////////////////////////////// +// class public + ++ (TTSpeechBubbleShape*)shapeWithRadius:(CGFloat)radius pointLocation:(CGFloat)pointLocation + pointAngle:(CGFloat)pointAngle pointSize:(CGSize)pointSize { + TTSpeechBubbleShape* shape = [[[TTSpeechBubbleShape alloc] init] autorelease]; + shape.radius = radius; + shape.pointLocation = pointLocation; + shape.pointAngle = pointAngle; + shape.pointSize = pointSize; + return shape; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////// +// private + +- (CGRect)subtractPointFromRect:(CGRect)rect { + CGFloat x = 0; + CGFloat y = 0; + CGFloat w = rect.size.width; + CGFloat h = rect.size.height; + + if ((_pointLocation >= 0 && _pointLocation < 45) + || (_pointLocation >= 315 && _pointLocation < 360)) { + if ((_pointAngle >= 270 && _pointAngle < 360) || (_pointAngle >= 0 && _pointAngle < 90)) { + x += _pointSize.width; + w -= _pointSize.width; + } + } else if (_pointLocation >= 45 && _pointLocation < 135) { + if (_pointAngle >= 0 && _pointAngle < 180) { + y += _pointSize.height; + h -= _pointSize.height; + } + } else if (_pointLocation >= 135 && _pointLocation < 225) { + if (_pointAngle >= 90 && _pointAngle < 270) { + w -= _pointSize.width; + } + } else if (_pointLocation >= 225 && _pointLocation <= 315) { + if (_pointAngle >= 180 && _pointAngle < 360) { + h -= _pointSize.height; + } + } + + return CGRectMake(x, y, w, h); +} + +- (void)addTopEdge:(CGSize)size lightSource:(NSInteger)lightSource toPath:(CGMutablePathRef)path + reset:(BOOL)reset { + CGFloat fw = size.width; + CGFloat fh = size.height; + CGFloat ph = _pointSize.height; + CGFloat pointX = 0; + + if (lightSource >= 0 && lightSource <= 90) { + if (reset) { + CGPathMoveToPoint(path, nil, RD(_radius), 0); + } + } else { + if (reset) { + CGPathMoveToPoint(path, nil, 0, RD(_radius)); + } + CGPathAddArcToPoint(path, nil, 0, 0, RD(_radius), 0, RD(_radius)); + } + + if (_pointLocation >= 45 && _pointLocation <= 135) { + ph = _pointAngle >= 0 && _pointAngle < 180 ? _pointSize.height : -_pointSize.height; + pointX = ((_pointLocation-45)/90) * fw; + + CGPathAddLineToPoint(path, nil, pointX-floor(_pointSize.width/2), 0); + CGPathAddLineToPoint(path, nil, pointX, -ph); + CGPathAddLineToPoint(path, nil, pointX+floor(_pointSize.width/2), 0); + } + + CGPathAddArcToPoint(path, nil, fw, 0, fw, RD(_radius), RD(_radius)); +} + +- (void)addRightEdge:(CGSize)size lightSource:(NSInteger)lightSource toPath:(CGMutablePathRef)path + reset:(BOOL)reset { + CGFloat fw = size.width; + CGFloat fh = size.height; + + if (reset) { + CGPathMoveToPoint(path, nil, fw, RD(_radius)); + } + + CGPathAddArcToPoint(path, nil, fw, fh, fw-RD(_radius), fh, RD(_radius)); +} + +- (void)addBottomEdge:(CGSize)size lightSource:(NSInteger)lightSource toPath:(CGMutablePathRef)path + reset:(BOOL)reset { + CGFloat fw = size.width; + CGFloat fh = size.height; + CGFloat ph = _pointSize.height; + CGFloat pointX = 0; + + if (reset) { + CGPathMoveToPoint(path, nil, fw-RD(_radius), fh); + } + + if (_pointLocation >= 225 && _pointLocation <= 315) { + if (_pointAngle >= 0 && _pointAngle < 180) { + ph = _pointSize.height; + } else { + ph = -_pointSize.height; + } + + pointX = fw - (((_pointLocation-225)/90) * fw); + CGPathAddArcToPoint(path, nil, fw, fh, floor(fw/2), fh, RD(_radius)); + CGPathAddLineToPoint(path, nil, pointX+floor(_pointSize.width/2), fh); + CGPathAddLineToPoint(path, nil, pointX, fh-ph); + CGPathAddLineToPoint(path, nil, pointX-floor(_pointSize.width/2), fh); + CGPathAddLineToPoint(path, nil, RD(_radius), fh); + } + + CGPathAddArcToPoint(path, nil, 0, fh, 0, fh-RD(_radius), RD(_radius)); +} + +- (void)addLeftEdge:(CGSize)size lightSource:(NSInteger)lightSource toPath:(CGMutablePathRef)path + reset:(BOOL)reset { + CGFloat fh = size.height; + + if (reset) { + CGPathMoveToPoint(path, nil, 0, fh-RD(_radius)); + } + + if (lightSource >= 0 && lightSource <= 90) { + CGPathAddArcToPoint(path, nil, 0, 0, RD(_radius), 0, RD(_radius)); + } else { + CGPathAddLineToPoint(path, nil, 0, RD(_radius)); + } +} + +- (void)addToPath:(CGSize)size path:(CGMutablePathRef)path { + [self addTopEdge:size lightSource:0 toPath:path reset:YES]; + [self addRightEdge:size lightSource:0 toPath:path reset:NO]; + [self addBottomEdge:size lightSource:0 toPath:path reset:NO]; + [self addLeftEdge:size lightSource:0 toPath:path reset:NO]; +} + +- (void)drawPath:(CGMutablePathRef)path inRect:(CGRect)rect { + CGContextRef context = UIGraphicsGetCurrentContext(); + CGContextTranslateCTM(context, rect.origin.x, rect.origin.y); + CGContextAddPath(context, path); + CGContextTranslateCTM(context, -rect.origin.x, -rect.origin.y); +} + +/////////////////////////////////////////////////////////////////////////////////////////////////// +// public + +- (void)addToPath:(CGRect)rect { + [self openPath:rect]; + + CGMutablePathRef path = CGPathCreateMutable(); + rect = [self subtractPointFromRect:rect]; + [self addToPath:rect.size path:path]; + CGPathCloseSubpath(path); + [self drawPath:path inRect:rect]; + CGPathRelease(path); + + [self closePath:rect]; +} + +- (void)addInverseToPath:(CGRect)rect { + [self openPath:rect]; + + CGMutablePathRef path = CGPathCreateMutable(); + rect = [self subtractPointFromRect:rect]; + CGRect shadowRect = CGRectMake(-kInsetWidth, -kInsetWidth, + rect.size.width+kInsetWidth*2, rect.size.height+kInsetWidth*2); + CGPathAddRect(path, nil, shadowRect); + [self addToPath:rect.size path:path]; + CGPathCloseSubpath(path); + [self drawPath:path inRect:rect]; + CGPathRelease(path); + + [self closePath:rect]; +} + +- (void)addTopEdgeToPath:(CGRect)rect lightSource:(NSInteger)lightSource { + rect = [self subtractPointFromRect:rect]; + + CGMutablePathRef path = CGPathCreateMutable(); + [self addTopEdge:rect.size lightSource:lightSource toPath:path reset:YES]; + [self drawPath:path inRect:rect]; + CGPathRelease(path); +} + +- (void)addRightEdgeToPath:(CGRect)rect lightSource:(NSInteger)lightSource { + rect = [self subtractPointFromRect:rect]; + + CGMutablePathRef path = CGPathCreateMutable(); + [self addRightEdge:rect.size lightSource:lightSource toPath:path reset:YES]; + [self drawPath:path inRect:rect]; + CGPathRelease(path); +} + +- (void)addBottomEdgeToPath:(CGRect)rect lightSource:(NSInteger)lightSource { + rect = [self subtractPointFromRect:rect]; + + CGMutablePathRef path = CGPathCreateMutable(); + [self addBottomEdge:rect.size lightSource:lightSource toPath:path reset:YES]; + [self drawPath:path inRect:rect]; + CGPathRelease(path); +} + +- (void)addLeftEdgeToPath:(CGRect)rect lightSource:(NSInteger)lightSource { + rect = [self subtractPointFromRect:rect]; + + CGMutablePathRef path = CGPathCreateMutable(); + [self addLeftEdge:rect.size lightSource:lightSource toPath:path reset:YES]; + [self drawPath:path inRect:rect]; + CGPathRelease(path); +} + +@end diff --git a/src/TTTableField.m b/src/TTTableField.m index 4844e27044..d40c569a46 100644 --- a/src/TTTableField.m +++ b/src/TTTableField.m @@ -364,7 +364,7 @@ - (void)dealloc { @implementation TTStyledTextTableField -@synthesize styledText = _styledText; +@synthesize styledText = _styledText, margin = _margin, padding = _padding; - (id)initWithStyledText:(TTStyledText*)styledText { if (self = [self init]) { @@ -383,6 +383,8 @@ - (id)initWithStyledText:(TTStyledText*)styledText url:(NSString*)url { - (id)init { if (self = [super init]) { _styledText = nil; + _margin = UIEdgeInsetsZero; + _padding = UIEdgeInsetsMake(10, 10, 10, 10); } return self; } diff --git a/src/TTTableFieldCell.m b/src/TTTableFieldCell.m index 8e731422a0..68b6bdf831 100644 --- a/src/TTTableFieldCell.m +++ b/src/TTTableFieldCell.m @@ -183,13 +183,14 @@ + (CGFloat)tableView:(UITableView*)tableView rowHeightForItem:(id)item { field.styledText.font = TTSTYLEVAR(font); CGFloat padding = tableView.style == UITableViewStyleGrouped ? kGroupMargin*2 : 0; + padding += field.padding.left + field.padding.right; if (field.url) { padding += kDisclosureIndicatorWidth; } field.styledText.width = tableView.width - padding; - return field.styledText.height; + return field.styledText.height + field.padding.top + field.padding.bottom; } /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -214,7 +215,15 @@ - (void)dealloc { - (void)layoutSubviews { [super layoutSubviews]; - _label.frame = self.contentView.bounds; + TTStyledTextTableField* field = self.object; + _label.frame = CGRectOffset(self.contentView.bounds, field.margin.left, field.margin.top); +} + +-(void)didMoveToSuperview { + [super didMoveToSuperview]; + if (self.superview && [(UITableView*)self.superview style] == UITableViewStylePlain) { + _label.backgroundColor = self.superview.backgroundColor; + } } /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -226,6 +235,7 @@ - (void)setObject:(id)object { TTStyledTextTableField* field = object; _label.text = field.styledText; + _label.contentInset = field.padding; } } diff --git a/src/Three20/TTShape.h b/src/Three20/TTShape.h index dbcaa049af..d859df173f 100644 --- a/src/Three20/TTShape.h +++ b/src/Three20/TTShape.h @@ -73,3 +73,22 @@ + (TTRoundedLeftArrowShape*)shapeWithRadius:(CGFloat)radius; @end + +/////////////////////////////////////////////////////////////////////////////////////////////////// + +@interface TTSpeechBubbleShape : TTShape { + CGFloat _radius; + CGFloat _pointLocation; + CGFloat _pointAngle; + CGSize _pointSize; +} + +@property(nonatomic) CGFloat radius; +@property(nonatomic) CGFloat pointLocation; +@property(nonatomic) CGFloat pointAngle; +@property(nonatomic) CGSize pointSize; + ++ (TTSpeechBubbleShape*)shapeWithRadius:(CGFloat)radius pointLocation:(CGFloat)pointLocation + pointAngle:(CGFloat)pointAngle pointSize:(CGSize)pointSize; + +@end diff --git a/src/Three20/TTTableField.h b/src/Three20/TTTableField.h index bbf3c401f1..bebb1d029c 100644 --- a/src/Three20/TTTableField.h +++ b/src/Three20/TTTableField.h @@ -18,6 +18,21 @@ @interface TTTextTableField : TTTableField @end +@interface TTStyledTextTableField : TTTableField { + TTStyledText* _styledText; + UIEdgeInsets _margin; + UIEdgeInsets _padding; +} + +@property(nonatomic,retain) TTStyledText* styledText; +@property(nonatomic) UIEdgeInsets margin; +@property(nonatomic) UIEdgeInsets padding; + +- (id)initWithStyledText:(TTStyledText*)text; +- (id)initWithStyledText:(TTStyledText*)text url:(NSString*)url; + +@end + @interface TTGrayTextTableField : TTTextTableField @end @@ -154,14 +169,3 @@ - (id)initWithText:(NSString*)text on:(BOOL)on; @end - -@interface TTStyledTextTableField : TTTableField { - TTStyledText* _styledText; -} - -@property(nonatomic,retain) TTStyledText* styledText; - -- (id)initWithStyledText:(TTStyledText*)text; -- (id)initWithStyledText:(TTStyledText*)text url:(NSString*)url; - -@end diff --git a/src/UIViewControllerAdditions.m b/src/UIViewControllerAdditions.m index fb7fa6f27d..a4b2a97e54 100644 --- a/src/UIViewControllerAdditions.m +++ b/src/UIViewControllerAdditions.m @@ -46,17 +46,18 @@ - (UIViewController*)nextViewController { - (void)alert:(NSString*)message title:(NSString*)title delegate:(id)delegate { if (message) { UIAlertView* alert = [[[UIAlertView alloc] initWithTitle:title message:message - delegate:delegate cancelButtonTitle:@"Ok" otherButtonTitles:nil] autorelease]; + delegate:delegate cancelButtonTitle:TTLocalizedString(@"OK", @"") otherButtonTitles:nil] + autorelease]; [alert show]; } } - (void)alert:(NSString*)message { - [self alert:message title:@"Alert" delegate:nil]; + [self alert:message title:TTLocalizedString(@"Alert", @"") delegate:nil]; } - (void)alertError:(NSString*)message { - [self alert:message title:@"Error" delegate:nil]; + [self alert:message title:TTLocalizedString(@"Error", @"") delegate:nil]; } - (void)showBars:(BOOL)show animated:(BOOL)animated {