OLD | NEW |
1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #import "ios/chrome/today_extension/interactive_label.h" | 5 #import "ios/chrome/today_extension/interactive_label.h" |
6 | 6 |
7 #import "base/mac/scoped_block.h" | 7 #import "base/mac/scoped_block.h" |
8 #import "base/mac/scoped_nsobject.h" | 8 #import "base/mac/scoped_nsobject.h" |
9 #import "ios/chrome/common/string_util.h" | 9 #import "ios/chrome/common/string_util.h" |
10 #include "ios/chrome/today_extension/transparent_button.h" | 10 #include "ios/chrome/today_extension/transparent_button.h" |
(...skipping 16 matching lines...) Expand all Loading... |
27 - (BOOL)canBecomeFirstResponder { | 27 - (BOOL)canBecomeFirstResponder { |
28 return NO; | 28 return NO; |
29 } | 29 } |
30 | 30 |
31 @end | 31 @end |
32 | 32 |
33 @implementation InteractiveLabel { | 33 @implementation InteractiveLabel { |
34 base::scoped_nsobject<NSString> _labelString; | 34 base::scoped_nsobject<NSString> _labelString; |
35 base::scoped_nsobject<NSString> _buttonString; | 35 base::scoped_nsobject<NSString> _buttonString; |
36 base::scoped_nsobject<UITextView> _label; | 36 base::scoped_nsobject<UITextView> _label; |
37 base::mac::ScopedBlock<ProceduralBlock> _linkBlock; | 37 ProceduralBlock _linkBlock; |
38 base::mac::ScopedBlock<ProceduralBlock> _buttonBlock; | 38 ProceduralBlock _buttonBlock; |
39 base::scoped_nsobject<TransparentButton> _activationButton; | 39 base::scoped_nsobject<TransparentButton> _activationButton; |
40 NSRange _buttonRange; | 40 NSRange _buttonRange; |
41 base::scoped_nsobject<NSMutableAttributedString> _attributedText; | 41 base::scoped_nsobject<NSMutableAttributedString> _attributedText; |
42 UIEdgeInsets _insets; | 42 UIEdgeInsets _insets; |
43 CGFloat _currentWidth; | 43 CGFloat _currentWidth; |
44 | 44 |
45 // These constraints set the position of the button inside | 45 // These constraints set the position of the button inside |
46 base::scoped_nsobject<NSLayoutConstraint> _buttonTopConstraint; | 46 base::scoped_nsobject<NSLayoutConstraint> _buttonTopConstraint; |
47 base::scoped_nsobject<NSLayoutConstraint> _buttonLeftConstraint; | 47 base::scoped_nsobject<NSLayoutConstraint> _buttonLeftConstraint; |
48 base::scoped_nsobject<NSLayoutConstraint> _buttonHeightConstraint; | 48 base::scoped_nsobject<NSLayoutConstraint> _buttonHeightConstraint; |
(...skipping 11 matching lines...) Expand all Loading... |
60 self = [super initWithFrame:frame]; | 60 self = [super initWithFrame:frame]; |
61 if (self) { | 61 if (self) { |
62 _insets = insets; | 62 _insets = insets; |
63 _currentWidth = frame.size.width; | 63 _currentWidth = frame.size.width; |
64 // When the first character of the UITextView text as a NSLinkAttributeName | 64 // When the first character of the UITextView text as a NSLinkAttributeName |
65 // attribute, the lineSpacing attribute of the paragraph style is ignored. | 65 // attribute, the lineSpacing attribute of the paragraph style is ignored. |
66 // Add a zero width space so the first character is never in a link. | 66 // Add a zero width space so the first character is never in a link. |
67 NSString* prefixedString = | 67 NSString* prefixedString = |
68 [NSString stringWithFormat:@"\u200B%@", labelString]; | 68 [NSString stringWithFormat:@"\u200B%@", labelString]; |
69 _labelString.reset([prefixedString copy]); | 69 _labelString.reset([prefixedString copy]); |
70 _linkBlock.reset(linkBlock, base::scoped_policy::RETAIN); | 70 _linkBlock = [linkBlock copy]; |
71 | 71 |
72 _label.reset([[NoSelectionUITextView alloc] initWithFrame:CGRectZero]); | 72 _label.reset([[NoSelectionUITextView alloc] initWithFrame:CGRectZero]); |
73 [_label setTranslatesAutoresizingMaskIntoConstraints:NO]; | 73 [_label setTranslatesAutoresizingMaskIntoConstraints:NO]; |
74 [_label setDelegate:self]; | 74 [_label setDelegate:self]; |
75 [_label setBackgroundColor:[UIColor clearColor]]; | 75 [_label setBackgroundColor:[UIColor clearColor]]; |
76 [_label setSelectable:YES]; | 76 [_label setSelectable:YES]; |
77 [_label setEditable:NO]; | 77 [_label setEditable:NO]; |
78 // We want to get rid of the padding of the text in the UITextView. | 78 // We want to get rid of the padding of the text in the UITextView. |
79 [_label setTextContainerInset:UIEdgeInsetsZero]; | 79 [_label setTextContainerInset:UIEdgeInsetsZero]; |
80 [[_label textContainer] setLineFragmentPadding:0]; | 80 [[_label textContainer] setLineFragmentPadding:0]; |
(...skipping 11 matching lines...) Expand all Loading... |
92 | 92 |
93 NSRange linkRange; | 93 NSRange linkRange; |
94 NSString* text = ParseStringWithLink(_labelString, &linkRange); | 94 NSString* text = ParseStringWithLink(_labelString, &linkRange); |
95 [_label setAccessibilityTraits:[_label accessibilityTraits] | | 95 [_label setAccessibilityTraits:[_label accessibilityTraits] | |
96 UIAccessibilityTraitStaticText]; | 96 UIAccessibilityTraitStaticText]; |
97 NSString* buttonText = nil; | 97 NSString* buttonText = nil; |
98 _buttonRange = NSMakeRange(0, 0); | 98 _buttonRange = NSMakeRange(0, 0); |
99 BOOL showButton = buttonString && buttonBlock; | 99 BOOL showButton = buttonString && buttonBlock; |
100 if (showButton) { | 100 if (showButton) { |
101 _buttonString.reset([buttonString copy]); | 101 _buttonString.reset([buttonString copy]); |
102 _buttonBlock.reset(buttonBlock, base::scoped_policy::RETAIN); | 102 _buttonBlock = [buttonBlock copy]; |
103 _activationButton.reset( | 103 _activationButton.reset( |
104 [[TransparentButton alloc] initWithFrame:CGRectZero]); | 104 [[TransparentButton alloc] initWithFrame:CGRectZero]); |
105 [_activationButton addTarget:self | 105 [_activationButton addTarget:self |
106 action:@selector(buttonPressed:) | 106 action:@selector(buttonPressed:) |
107 forControlEvents:UIControlEventTouchUpInside]; | 107 forControlEvents:UIControlEventTouchUpInside]; |
108 [_activationButton setBackgroundColor:[UIColor clearColor]]; | 108 [_activationButton setBackgroundColor:[UIColor clearColor]]; |
109 [_activationButton setInkColor:ui_util::InkColor()]; | 109 [_activationButton setInkColor:ui_util::InkColor()]; |
110 [_activationButton setCornerRadius:2]; | 110 [_activationButton setCornerRadius:2]; |
111 [_activationButton setBorderWidth:1]; | 111 [_activationButton setBorderWidth:1]; |
112 [_activationButton setBorderColor:ui_util::BorderColor()]; | 112 [_activationButton setBorderColor:ui_util::BorderColor()]; |
113 [self addSubview:_activationButton]; | 113 [self addSubview:_activationButton]; |
114 [self bringSubviewToFront:_activationButton]; | 114 [self bringSubviewToFront:_activationButton]; |
115 _buttonTopConstraint.reset([[[_activationButton topAnchor] | 115 _buttonTopConstraint.reset([[_activationButton topAnchor] |
116 constraintEqualToAnchor:[self topAnchor]] retain]); | 116 constraintEqualToAnchor:[self topAnchor]]); |
117 _buttonLeftConstraint.reset([[[_activationButton leftAnchor] | 117 _buttonLeftConstraint.reset([[_activationButton leftAnchor] |
118 constraintEqualToAnchor:[self leftAnchor]] retain]); | 118 constraintEqualToAnchor:[self leftAnchor]]); |
119 _buttonWidthConstraint.reset([[[_activationButton widthAnchor] | 119 _buttonWidthConstraint.reset( |
120 constraintEqualToConstant:0] retain]); | 120 [[_activationButton widthAnchor] constraintEqualToConstant:0]); |
121 _buttonHeightConstraint.reset([[[_activationButton heightAnchor] | 121 _buttonHeightConstraint.reset( |
122 constraintEqualToConstant:0] retain]); | 122 [[_activationButton heightAnchor] constraintEqualToConstant:0]); |
123 [NSLayoutConstraint activateConstraints:@[ | 123 [NSLayoutConstraint activateConstraints:@[ |
124 _buttonTopConstraint, _buttonLeftConstraint, _buttonWidthConstraint, | 124 _buttonTopConstraint, _buttonLeftConstraint, _buttonWidthConstraint, |
125 _buttonHeightConstraint | 125 _buttonHeightConstraint |
126 ]]; | 126 ]]; |
127 | 127 |
128 // Add two spaces before and after the button label to add padding to the | 128 // Add two spaces before and after the button label to add padding to the |
129 // button. | 129 // button. |
130 buttonText = [NSString stringWithFormat:@" %@ ", _buttonString.get()]; | 130 buttonText = [NSString stringWithFormat:@" %@ ", _buttonString.get()]; |
131 // Replace spaces by non breaking spaces to prevent buttons from wrapping. | 131 // Replace spaces by non breaking spaces to prevent buttons from wrapping. |
132 buttonText = [buttonText stringByReplacingOccurrencesOfString:@" " | 132 buttonText = [buttonText stringByReplacingOccurrencesOfString:@" " |
(...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
226 [_buttonTopConstraint setConstant:buttonFrame.origin.y]; | 226 [_buttonTopConstraint setConstant:buttonFrame.origin.y]; |
227 [_buttonLeftConstraint setConstant:buttonFrame.origin.x]; | 227 [_buttonLeftConstraint setConstant:buttonFrame.origin.x]; |
228 [_buttonWidthConstraint setConstant:buttonFrame.size.width]; | 228 [_buttonWidthConstraint setConstant:buttonFrame.size.width]; |
229 [_buttonHeightConstraint setConstant:buttonFrame.size.height]; | 229 [_buttonHeightConstraint setConstant:buttonFrame.size.height]; |
230 } | 230 } |
231 } | 231 } |
232 | 232 |
233 - (BOOL)textView:(UITextView*)textView | 233 - (BOOL)textView:(UITextView*)textView |
234 shouldInteractWithURL:(NSURL*)URL | 234 shouldInteractWithURL:(NSURL*)URL |
235 inRange:(NSRange)characterRange { | 235 inRange:(NSRange)characterRange { |
236 _linkBlock.get()(); | 236 if (_linkBlock) |
| 237 _linkBlock(); |
237 return NO; | 238 return NO; |
238 } | 239 } |
239 | 240 |
240 - (void)buttonPressed:(id)sender { | 241 - (void)buttonPressed:(id)sender { |
241 _buttonBlock.get()(); | 242 if (_buttonBlock) |
| 243 _buttonBlock(); |
242 } | 244 } |
243 | 245 |
244 - (CGSize)intrinsicContentSize { | 246 - (CGSize)intrinsicContentSize { |
245 return [self sizeThatFits:CGSizeMake(_currentWidth, CGFLOAT_MAX)]; | 247 return [self sizeThatFits:CGSizeMake(_currentWidth, CGFLOAT_MAX)]; |
246 } | 248 } |
247 | 249 |
248 - (CGSize)sizeThatFits:(CGSize)size { | 250 - (CGSize)sizeThatFits:(CGSize)size { |
249 if (![_attributedText length]) | 251 if (![_attributedText length]) |
250 return CGSizeMake(size.width, | 252 return CGSizeMake(size.width, |
251 MIN(_insets.top + _insets.bottom, size.height)); | 253 MIN(_insets.top + _insets.bottom, size.height)); |
252 | 254 |
253 // -sizeThatFits: doesn't behaves properly with UITextView. | 255 // -sizeThatFits: doesn't behaves properly with UITextView. |
254 // Therefore, we need to measure text size using | 256 // Therefore, we need to measure text size using |
255 // -boundingRectWithSize:options:context:. | 257 // -boundingRectWithSize:options:context:. |
256 CGSize constraints = | 258 CGSize constraints = |
257 CGSizeMake(size.width - _insets.left - _insets.right, CGFLOAT_MAX); | 259 CGSizeMake(size.width - _insets.left - _insets.right, CGFLOAT_MAX); |
258 CGRect bounding = [_attributedText | 260 CGRect bounding = [_attributedText |
259 boundingRectWithSize:constraints | 261 boundingRectWithSize:constraints |
260 options:static_cast<NSStringDrawingOptions>( | 262 options:static_cast<NSStringDrawingOptions>( |
261 NSStringDrawingUsesLineFragmentOrigin | | 263 NSStringDrawingUsesLineFragmentOrigin | |
262 NSStringDrawingUsesFontLeading) | 264 NSStringDrawingUsesFontLeading) |
263 context:nil]; | 265 context:nil]; |
264 return CGSizeMake( | 266 return CGSizeMake( |
265 size.width, | 267 size.width, |
266 MIN(bounding.size.height + _insets.top + _insets.bottom, size.height)); | 268 MIN(bounding.size.height + _insets.top + _insets.bottom, size.height)); |
267 } | 269 } |
268 | 270 |
269 @end | 271 @end |
OLD | NEW |