Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(488)

Side by Side Diff: chrome/browser/ui/cocoa/toolbar/app_toolbar_button_icon.mm

Issue 2859903003: [Mac] App Menu Animated Icon (Closed)
Patch Set: Clean up Created 3 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2017 The Chromium Authors. All rights reserved.
Robert Sesek 2017/05/03 22:44:29 Are other platforms going to use the same spec? Sh
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #import "chrome/browser/ui/cocoa/toolbar/app_toolbar_button_icon.h"
6
7 #include "base/memory/ptr_util.h"
8 #import "chrome/browser/ui/cocoa/toolbar/app_toolbar_button.h"
9 #include "skia/ext/skia_utils_mac.h"
10 #include "ui/gfx/animation/slide_animation.h"
11 #include "ui/gfx/animation/tween.h"
12
13 namespace {
14
15 // Duration of the open and close animations in ms.
16 constexpr float kOpenDurationMs = 733.0f;
17 constexpr float kCloseDurationMs = 283.0f;
18
19 // Duration of the color animation in ms.
20 constexpr float kColorDurationMs = 100.0f;
21
22 // The % the top and bottom dots need to be offset from the middle.
23 constexpr float kDotYOffset = 0.32f;
24
25 // Value of the stroke when the icon is opened or closed.
26 constexpr float kCloseStroke = 0.204f;
27 constexpr float kOpenStroke = 0.136f;
28
29 // Value of the width when the animation is fully opened.
30 constexpr float kOpenWidth = 0.52f;
31
32 // The delay of the color and dot animations in ms.
33 constexpr float kColorDelayMs = 33.33f;
34 constexpr float kDotDelayMs = 66.67f;
35
36 // The % of time it takes for each dot to animate to its full width.
37 constexpr float kTopWidthOpenInterval = 533.3f / kOpenDurationMs;
38 constexpr float kMiddleWidthOpenInterval = 383.3f / kOpenDurationMs;
39 constexpr float kBottomWidthOpenInterval = 400.0f / kOpenDurationMs;
40
41 // The % of time it takes for each dot to animate to its final stroke.
42 constexpr float kTopStrokeOpenInterval = 400.0f / kOpenDurationMs;
43 constexpr float kMiddleStrokeOpenInterval = 283.3f / kOpenDurationMs;
44 constexpr float kBottomStrokeOpenInterval = 266.7f / kOpenDurationMs;
45
46 // The % of time it takes for each dot to animate its width and stroke
47 // when the animation closes.
48 constexpr float kWidthStrokeCloseInterval = 150.0f / kCloseDurationMs;
49
50 // The radius of each dot.
51 constexpr float kDotRadius = 8.0f;
52
53 // The size of the icon.
54 constexpr float kIconSize = 16.0f;
55
56 } // namespace
57
58 AppMenuDot::AppMenuDot(base::TimeDelta delay,
59 float width_open_interval,
60 float stroke_open_interval)
61 : delay_(delay),
62 width_open_interval_(width_open_interval),
63 stroke_open_interval_(stroke_open_interval) {}
64
65 void AppMenuDot::DrawDot(NSPoint center_pt,
66 NSSize imageSize,
67 SkColor start_color,
68 SkColor target_color,
69 const gfx::SlideAnimation* animation) {
70 bool is_opening = animation->IsShowing();
71 float total_duration = is_opening ? kOpenDurationMs : kCloseDurationMs;
72 float width_duration =
73 is_opening ? width_open_interval_ : kWidthStrokeCloseInterval;
74 float stroke_duration =
75 is_opening ? stroke_open_interval_ : kWidthStrokeCloseInterval;
76
77 // When the animation is closing, each dot uses the remainder of the full
78 // delay period (2 * kDotDelayMs). The results should be (0->2x, 1x->1x,
79 // 2x->0).
80 base::TimeDelta delay =
81 is_opening ? delay_
82 : base::TimeDelta::FromMilliseconds(kDotDelayMs * 2) - delay_;
83 float progress =
84 animation->GetCurrentValue() - (delay.InMillisecondsF() / total_duration);
85
86 float width_progress = 0.0;
87 float stroke_progress = 0.0;
88 float color_progress = 0.0;
89
90 if (progress > 0) {
91 width_progress = std::min(1.0f, progress / width_duration);
92 stroke_progress = std::min(1.0f, progress / stroke_duration);
93
94 if (is_opening) {
95 float color_delay_interval = kColorDelayMs / total_duration;
96 float color_duration_interval = kColorDurationMs / total_duration;
97 if (progress > color_delay_interval) {
98 color_progress = std::min(
99 1.0f, (progress - color_delay_interval) / color_duration_interval);
100 }
101 }
102 }
103
104 float dot_height =
105 gfx::Tween::FloatValueBetween(stroke_progress, kCloseStroke, kOpenStroke);
106 dot_height *= imageSize.height;
107
108 float dot_width =
109 gfx::Tween::FloatValueBetween(width_progress, kCloseStroke, kOpenWidth);
110 dot_width *= imageSize.width;
111
112 SkColor color = is_opening ? gfx::Tween::ColorValueBetween(
113 color_progress, start_color, target_color)
114 : target_color;
115
116 NSRect rect =
117 NSMakeRect(center_pt.x - dot_width / 2.0f,
118 center_pt.y - dot_height / 2.0f, dot_width, dot_height);
119
120 [skia::SkColorToSRGBNSColor(color) set];
121 [[NSBezierPath bezierPathWithRoundedRect:rect
122 xRadius:kDotRadius
123 yRadius:kDotRadius] fill];
124 }
125
126 AppToolbarButtonIcon::AppToolbarButtonIcon(AppToolbarButton* owner,
127 SkColor start_color)
128 : animation_(base::MakeUnique<gfx::SlideAnimation>(this)),
129 bottom_dot_(base::TimeDelta(),
130 kBottomWidthOpenInterval,
131 kBottomStrokeOpenInterval),
132 center_dot_(base::TimeDelta::FromMilliseconds(kDotDelayMs),
133 kMiddleWidthOpenInterval,
134 kMiddleStrokeOpenInterval),
135 top_dot_(base::TimeDelta::FromMilliseconds(kDotDelayMs * 2),
136 kTopWidthOpenInterval,
137 kTopStrokeOpenInterval),
138 start_color_(start_color),
139 target_color_(start_color),
140 owner_(owner) {
141 DCHECK(owner_);
142 }
143
144 AppToolbarButtonIcon::~AppToolbarButtonIcon() {}
145
146 void AppToolbarButtonIcon::StartAnimation() {
147 if (!animation_->is_animating()) {
148 animation_->SetSlideDuration(kOpenDurationMs);
149 animation_->Show();
150 }
151 }
152
153 void AppToolbarButtonIcon::AnimationEnded(const gfx::Animation* animation) {
154 if (animation_->IsShowing()) {
155 animation_->SetSlideDuration(kCloseDurationMs);
156 animation_->Hide();
157 } else {
158 start_color_ = target_color_;
159 }
160 }
161
162 void AppToolbarButtonIcon::AnimationProgressed(
163 const gfx::Animation* animation) {
164 [owner_ setNeedsDisplay:YES];
165 }
166
167 void AppToolbarButtonIcon::DrawIcon(NSRect frame) {
168 NSSize size = NSMakeSize(kIconSize, kIconSize);
169 NSPoint center_pt =
170 NSMakePoint(NSWidth(frame) / 2.0f, NSHeight(frame) / 2.0f);
171
172 float y_offset = kDotYOffset * size.height;
173
174 center_dot_.DrawDot(center_pt, size, start_color_, target_color_,
175 animation_.get());
176 top_dot_.DrawDot(NSMakePoint(center_pt.x, center_pt.y - y_offset), size,
177 start_color_, target_color_, animation_.get());
178 bottom_dot_.DrawDot(NSMakePoint(center_pt.x, center_pt.y + y_offset), size,
179 start_color_, target_color_, animation_.get());
180 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698