OLD | NEW |
1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 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/browser/ui/toolbar/toolbar_tools_menu_button.h" | 5 #import "ios/chrome/browser/ui/toolbar/toolbar_tools_menu_button.h" |
6 | 6 |
7 #import <QuartzCore/CAAnimation.h> | 7 #import <QuartzCore/CAAnimation.h> |
8 #import <QuartzCore/CAMediaTimingFunction.h> | 8 #import <QuartzCore/CAMediaTimingFunction.h> |
9 | 9 |
10 #include "ios/chrome/browser/ui/toolbar/toolbar_button_tints.h" | 10 #include "ios/chrome/browser/ui/toolbar/toolbar_button_tints.h" |
11 | 11 |
12 #if !defined(__has_feature) || !__has_feature(objc_arc) | |
13 #error "This file requires ARC support." | |
14 #endif | |
15 | |
16 namespace { | 12 namespace { |
17 // The number of dots drawn. | 13 // The number of dots drawn. |
18 const int kNumberOfDots = 3; | 14 const int kNumberOfDots = 3; |
19 // Position of the topmost dot. | 15 // Position of the topmost dot. |
20 const CGFloat kDotOffsetX = 22; | 16 const CGFloat kDotOffsetX = 22; |
21 const CGFloat kDotOffsetY = 18; | 17 const CGFloat kDotOffsetY = 18; |
22 // Vertical space between dots. | 18 // Vertical space between dots. |
23 const CGFloat kVerticalSpaceBetweenDots = 6; | 19 const CGFloat kVerticalSpaceBetweenDots = 6; |
24 // The duration of the animation, in seconds. | 20 // The duration of the animation, in seconds. |
25 const CFTimeInterval kAnimationDuration = 1; | 21 const CFTimeInterval kAnimationDuration = 1; |
(...skipping 19 matching lines...) Expand all Loading... |
45 } // namespace | 41 } // namespace |
46 | 42 |
47 @interface ToolbarToolsMenuButton ()<CAAnimationDelegate> { | 43 @interface ToolbarToolsMenuButton ()<CAAnimationDelegate> { |
48 // The style of the toolbar the button is in. | 44 // The style of the toolbar the button is in. |
49 ToolbarControllerStyle style_; | 45 ToolbarControllerStyle style_; |
50 // Whether the tools menu is visible. | 46 // Whether the tools menu is visible. |
51 BOOL toolsMenuVisible_; | 47 BOOL toolsMenuVisible_; |
52 // Whether the reading list contains unseen items. | 48 // Whether the reading list contains unseen items. |
53 BOOL readingListContainsUnseenItems_; | 49 BOOL readingListContainsUnseenItems_; |
54 // The CALayers containing the drawn dots. | 50 // The CALayers containing the drawn dots. |
55 NSMutableArray<CAShapeLayer*>* pathLayers_; | 51 base::scoped_nsobject<CAShapeLayer> pathLayers_[kNumberOfDots]; |
56 // Whether the CALayers are being animated. | 52 // Whether the CALayers are being animated. |
57 BOOL animationOnGoing_; | 53 BOOL animationOnGoing_; |
58 } | 54 } |
59 // Updates the tint configuration based on the button's situation, e.g. whether | 55 // Updates the tint configuration based on the button's situation, e.g. whether |
60 // the tools menu is visible or not. | 56 // the tools menu is visible or not. |
61 - (void)updateTintOfButton; | 57 - (void)updateTintOfButton; |
62 // Initializes the pathLayers. | 58 // Initializes the pathLayers. |
63 - (void)initializeShapeLayers; | 59 - (void)initializeShapeLayers; |
64 // Returns a keyframe-based animation of the property identified by |keyPath|. | 60 // Returns a keyframe-based animation of the property identified by |keyPath|. |
65 // The animation immidiately sets the property's value to |initialValue|. | 61 // The animation immidiately sets the property's value to |initialValue|. |
(...skipping 12 matching lines...) Expand all Loading... |
78 | 74 |
79 - (instancetype)initWithFrame:(CGRect)frame | 75 - (instancetype)initWithFrame:(CGRect)frame |
80 style:(ToolbarControllerStyle)style { | 76 style:(ToolbarControllerStyle)style { |
81 if (self = [super initWithFrame:frame]) { | 77 if (self = [super initWithFrame:frame]) { |
82 style_ = style; | 78 style_ = style; |
83 | 79 |
84 [self setTintColor:toolbar::NormalButtonTint(style_) | 80 [self setTintColor:toolbar::NormalButtonTint(style_) |
85 forState:UIControlStateNormal]; | 81 forState:UIControlStateNormal]; |
86 [self setTintColor:toolbar::HighlighButtonTint(style_) | 82 [self setTintColor:toolbar::HighlighButtonTint(style_) |
87 forState:UIControlStateHighlighted]; | 83 forState:UIControlStateHighlighted]; |
88 pathLayers_ = [[NSMutableArray alloc] initWithCapacity:kNumberOfDots]; | |
89 } | 84 } |
90 return self; | 85 return self; |
91 } | 86 } |
92 | 87 |
93 - (void)setToolsMenuIsVisible:(BOOL)toolsMenuVisible { | 88 - (void)setToolsMenuIsVisible:(BOOL)toolsMenuVisible { |
94 toolsMenuVisible_ = toolsMenuVisible; | 89 toolsMenuVisible_ = toolsMenuVisible; |
95 [self updateTintOfButton]; | 90 [self updateTintOfButton]; |
96 } | 91 } |
97 | 92 |
98 - (void)setReadingListContainsUnseenItems:(BOOL)readingListContainsUnseenItems { | 93 - (void)setReadingListContainsUnseenItems:(BOOL)readingListContainsUnseenItems { |
(...skipping 12 matching lines...) Expand all Loading... |
111 [self setTintColor:toolbar::HighlighButtonTint(style_) | 106 [self setTintColor:toolbar::HighlighButtonTint(style_) |
112 forState:UIControlStateNormal]; | 107 forState:UIControlStateNormal]; |
113 } else { | 108 } else { |
114 [self setTintColor:toolbar::NormalButtonTint(style_) | 109 [self setTintColor:toolbar::NormalButtonTint(style_) |
115 forState:UIControlStateNormal]; | 110 forState:UIControlStateNormal]; |
116 } | 111 } |
117 } | 112 } |
118 | 113 |
119 - (void)initializeShapeLayers { | 114 - (void)initializeShapeLayers { |
120 for (int i = 0; i < kNumberOfDots; i++) { | 115 for (int i = 0; i < kNumberOfDots; i++) { |
121 CAShapeLayer* pathLayer = pathLayers_[i]; | 116 base::scoped_nsobject<CAShapeLayer>& pathLayer = pathLayers_[i]; |
122 if (pathLayer) { | 117 if (pathLayer) { |
123 [pathLayer removeFromSuperlayer]; | 118 [pathLayer removeFromSuperlayer]; |
124 } | 119 } |
125 | 120 |
126 const CGFloat x = kDotOffsetX; | 121 const CGFloat x = kDotOffsetX; |
127 const CGFloat y = kDotOffsetY + kVerticalSpaceBetweenDots * i; | 122 const CGFloat y = kDotOffsetY + kVerticalSpaceBetweenDots * i; |
128 | 123 |
129 UIBezierPath* path = [UIBezierPath bezierPath]; | 124 UIBezierPath* path = [UIBezierPath bezierPath]; |
130 [path moveToPoint:CGPointMake(x - kMaxWidthOfSegment * 0.5, y)]; | 125 [path moveToPoint:CGPointMake(x - kMaxWidthOfSegment * 0.5, y)]; |
131 [path addLineToPoint:CGPointMake(x + kMaxWidthOfSegment * 0.5, y)]; | 126 [path addLineToPoint:CGPointMake(x + kMaxWidthOfSegment * 0.5, y)]; |
132 | 127 |
133 pathLayer = [CAShapeLayer layer]; | 128 pathLayer.reset([[CAShapeLayer layer] retain]); |
134 [pathLayer setFrame:self.bounds]; | 129 [pathLayer setFrame:self.bounds]; |
135 [pathLayer setPath:path.CGPath]; | 130 [pathLayer setPath:path.CGPath]; |
136 [pathLayer setStrokeColor:[self.tintColor CGColor]]; | 131 [pathLayer setStrokeColor:[self.tintColor CGColor]]; |
137 [pathLayer setFillColor:nil]; | 132 [pathLayer setFillColor:nil]; |
138 [pathLayer setLineWidth:kLineWidthAtRest]; | 133 [pathLayer setLineWidth:kLineWidthAtRest]; |
139 [pathLayer setLineCap:kCALineCapRound]; | 134 [pathLayer setLineCap:kCALineCapRound]; |
140 [pathLayer setStrokeStart:kStrokeStartAtRest]; | 135 [pathLayer setStrokeStart:kStrokeStartAtRest]; |
141 [pathLayer setStrokeEnd:kStrokeEndAtRest]; | 136 [pathLayer setStrokeEnd:kStrokeEndAtRest]; |
142 [self.layer addSublayer:pathLayer]; | 137 [self.layer addSublayer:pathLayer.get()]; |
143 pathLayers_[i] = pathLayer; | |
144 } | 138 } |
145 } | 139 } |
146 | 140 |
147 - (CAAnimation*)animationWithInitialValue:(id)initialValue | 141 - (CAAnimation*)animationWithInitialValue:(id)initialValue |
148 intermediaryValue:(id)intermediaryValue | 142 intermediaryValue:(id)intermediaryValue |
149 finalValue:(id)finalValue | 143 finalValue:(id)finalValue |
150 frameStart:(int)frameStart | 144 frameStart:(int)frameStart |
151 forKeyPath:(NSString*)keyPath { | 145 forKeyPath:(NSString*)keyPath { |
152 // The property is animated the following way: | 146 // The property is animated the following way: |
153 // | 147 // |
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
205 #endif | 199 #endif |
206 | 200 |
207 return animation; | 201 return animation; |
208 } | 202 } |
209 | 203 |
210 - (void)animateToColor:(UIColor*)targetColor { | 204 - (void)animateToColor:(UIColor*)targetColor { |
211 animationOnGoing_ = YES; | 205 animationOnGoing_ = YES; |
212 | 206 |
213 // Add four animations for each stroke. | 207 // Add four animations for each stroke. |
214 for (int i = 0; i < kNumberOfDots; i++) { | 208 for (int i = 0; i < kNumberOfDots; i++) { |
215 CAShapeLayer* pathLayer = pathLayers_[i]; | 209 base::scoped_nsobject<CAShapeLayer>& pathLayer = pathLayers_[i]; |
| 210 DCHECK(pathLayer.get()); |
216 const int frameStart = | 211 const int frameStart = |
217 (kNumberOfDots - i) * kFramesBetweenAnimationOfEachDot; | 212 (kNumberOfDots - i) * kFramesBetweenAnimationOfEachDot; |
218 | 213 |
219 // Start of the stroke animation. | 214 // Start of the stroke animation. |
220 CAAnimation* strokeStartAnimation = | 215 CAAnimation* strokeStartAnimation = |
221 [self animationWithInitialValue:@(kStrokeStartAtRest) | 216 [self animationWithInitialValue:@(kStrokeStartAtRest) |
222 intermediaryValue:@(kStrokeStartAtApogee) | 217 intermediaryValue:@(kStrokeStartAtApogee) |
223 finalValue:@(kStrokeStartAtRest) | 218 finalValue:@(kStrokeStartAtRest) |
224 frameStart:frameStart | 219 frameStart:frameStart |
225 forKeyPath:@"strokeStart"]; | 220 forKeyPath:@"strokeStart"]; |
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
285 #pragma mark - CAAnimationDelegate | 280 #pragma mark - CAAnimationDelegate |
286 | 281 |
287 - (void)animationDidStop:(CAAnimation*)animation finished:(BOOL)flag { | 282 - (void)animationDidStop:(CAAnimation*)animation finished:(BOOL)flag { |
288 animationOnGoing_ = NO; | 283 animationOnGoing_ = NO; |
289 // Recreate the CAShapeLayers in case the tint code changed while the | 284 // Recreate the CAShapeLayers in case the tint code changed while the |
290 // animation was going on. | 285 // animation was going on. |
291 [self initializeShapeLayers]; | 286 [self initializeShapeLayers]; |
292 } | 287 } |
293 | 288 |
294 @end | 289 @end |
OLD | NEW |