1 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "chrome/browser/ui/toolbar/wrench_icon_painter.h"
6
7 #include "grit/theme_resources.h"
8 #include "ui/base/theme_provider.h"
9 #include "ui/gfx/animation/multi_animation.h"
10 #include "ui/gfx/canvas.h"
11 #include "ui/gfx/image/image_skia.h"
12 #include "ui/gfx/rect.h"
13
14 namespace {
15
16 // The wrench icon is made up of this many bars stacked vertically.
17 const int kBarCount = 3;
18
19 // |value| is the animation progress from 0 to 1. |index| is the index of the
20 // bar being drawn. This function returns a new progress value (from 0 to 1)
21 // such that bars appear staggered.
GetStaggeredValue(double value,int index)22 double GetStaggeredValue(double value, int index) {
23 // When animating the wrench icon's bars the bars are staggered by this
24 // factor.
25 const double kStaggerFactor = 0.15;
26 double maxStaggeredValue = 1.0 - (kBarCount - 1) * kStaggerFactor;
27 double staggeredValue = (value - kStaggerFactor * index) / maxStaggeredValue;
28 return std::min(1.0, std::max(0.0, staggeredValue));
29 }
30
31 } // namespace
32
33 // static
SeverityFromUpgradeLevel(UpgradeDetector::UpgradeNotificationAnnoyanceLevel level)34 WrenchIconPainter::Severity WrenchIconPainter::SeverityFromUpgradeLevel(
35 UpgradeDetector::UpgradeNotificationAnnoyanceLevel level) {
36 switch (level) {
37 case UpgradeDetector::UPGRADE_ANNOYANCE_NONE:
38 return SEVERITY_NONE;
39 case UpgradeDetector::UPGRADE_ANNOYANCE_LOW:
40 return SEVERITY_LOW;
41 case UpgradeDetector::UPGRADE_ANNOYANCE_ELEVATED:
42 return SEVERITY_MEDIUM;
43 case UpgradeDetector::UPGRADE_ANNOYANCE_HIGH:
44 return SEVERITY_HIGH;
45 case UpgradeDetector::UPGRADE_ANNOYANCE_SEVERE:
46 return SEVERITY_HIGH;
47 case UpgradeDetector::UPGRADE_ANNOYANCE_CRITICAL:
48 return SEVERITY_HIGH;
49 }
50 NOTREACHED();
51 return SEVERITY_NONE;
52 }
53
54 // static
ShouldAnimateUpgradeLevel(UpgradeDetector::UpgradeNotificationAnnoyanceLevel level)55 bool WrenchIconPainter::ShouldAnimateUpgradeLevel(
56 UpgradeDetector::UpgradeNotificationAnnoyanceLevel level) {
57 bool should_animate = true;
58 if (level == UpgradeDetector::UPGRADE_ANNOYANCE_LOW) {
59 // Only animate low severity upgrades once.
60 static bool should_animate_low_severity = true;
61 should_animate = should_animate_low_severity;
62 should_animate_low_severity = false;
63 }
64 return should_animate;
65 }
66
67 // static
GlobalErrorSeverity()68 WrenchIconPainter::Severity WrenchIconPainter::GlobalErrorSeverity() {
69 // If you change this make sure to also change the menu icon and the bubble
70 // icon.
71 return SEVERITY_MEDIUM;
72 }
73
WrenchIconPainter(Delegate * delegate)74 WrenchIconPainter::WrenchIconPainter(Delegate* delegate)
75 : delegate_(delegate),
76 severity_(SEVERITY_NONE) {
77 }
78
~WrenchIconPainter()79 WrenchIconPainter::~WrenchIconPainter() {}
80
SetSeverity(Severity severity,bool animate)81 void WrenchIconPainter::SetSeverity(Severity severity, bool animate) {
82 if (severity_ == severity)
83 return;
84
85 severity_ = severity;
86 delegate_->ScheduleWrenchIconPaint();
87 animation_.reset();
88 if (severity_ == SEVERITY_NONE || !animate)
89 return;
90
91 gfx::MultiAnimation::Parts parts;
92 // Animate the bars left to right.
93 parts.push_back(gfx::MultiAnimation::Part(1300, gfx::Tween::LINEAR));
94 // Fade out animation.
95 parts.push_back(gfx::MultiAnimation::Part(1000, gfx::Tween::EASE_IN));
96 // Again, animate the bars left to right.
97 parts.push_back(gfx::MultiAnimation::Part(1300, gfx::Tween::LINEAR));
98
99 animation_.reset(
100 new gfx::MultiAnimation(parts, base::TimeDelta::FromMilliseconds(40)));
101 animation_->set_delegate(this);
102 animation_->set_continuous(false);
103 animation_->Start();
104 }
105
Paint(gfx::Canvas * canvas,ui::ThemeProvider * theme_provider,const gfx::Rect & rect,BezelType bezel_type)106 void WrenchIconPainter::Paint(gfx::Canvas* canvas,
107 ui::ThemeProvider* theme_provider,
108 const gfx::Rect& rect,
109 BezelType bezel_type) {
110 gfx::Point center = rect.CenterPoint();
111
112 // Bezel.
113 if (bezel_type != BEZEL_NONE) {
114 gfx::ImageSkia* image = theme_provider->GetImageSkiaNamed(
115 bezel_type == BEZEL_HOVER ? IDR_TOOLBAR_BEZEL_HOVER
116 : IDR_TOOLBAR_BEZEL_PRESSED);
117 canvas->DrawImageInt(*image,
118 center.x() - image->width() / 2,
119 center.y() - image->height() / 2);
120 }
121
122 // The bars with no color.
123 {
124 gfx::ImageSkia* image = theme_provider->GetImageSkiaNamed(IDR_TOOLS_BAR);
125 int x = center.x() - image->width() / 2;
126 int y = center.y() - image->height() * kBarCount / 2;
127 for (int i = 0; i < kBarCount; ++i) {
128 canvas->DrawImageInt(*image, x, y);
129 y += image->height();
130 }
131 }
132
133 // The bars with color based on severity.
134 int severity_image_id = GetCurrentSeverityImageID();
135 if (severity_image_id) {
136 gfx::ImageSkia* image =
137 theme_provider->GetImageSkiaNamed(severity_image_id);
138 int x = center.x() - image->width() / 2;
139 int y = center.y() - image->height() * kBarCount / 2;
140 for (int i = 0; i < kBarCount; ++i) {
141 SkPaint paint;
142 int width = image->width();
143
144 if (animation_ && animation_->is_animating()) {
145 if (animation_->current_part_index() % 2 == 1) {
146 // Fade out.
147 int alpha = animation_->CurrentValueBetween(0xFF, 0);
148 if (alpha == 0)
149 continue;
150 paint.setAlpha(alpha);
151 } else {
152 // Stagger the widths.
153 width = image->width() *
154 GetStaggeredValue(animation_->GetCurrentValue(), i);
155 if (width == 0)
156 continue;
157 }
158 }
159
160 canvas->DrawImageInt(*image, 0, 0, width, image->height(),
161 x, y, width, image->height(), false, paint);
162 y += image->height();
163 }
164 }
165
166 if (!badge_.isNull())
167 canvas->DrawImageInt(badge_, 0, 0);
168 }
169
AnimationProgressed(const gfx::Animation * animation)170 void WrenchIconPainter::AnimationProgressed(const gfx::Animation* animation) {
171 delegate_->ScheduleWrenchIconPaint();
172 }
173
GetCurrentSeverityImageID() const174 int WrenchIconPainter::GetCurrentSeverityImageID() const {
175 switch (severity_) {
176 case SEVERITY_NONE:
177 return 0;
178 case SEVERITY_LOW:
179 return IDR_TOOLS_BAR_LOW;
180 case SEVERITY_MEDIUM:
181 return IDR_TOOLS_BAR_MEDIUM;
182 case SEVERITY_HIGH:
183 return IDR_TOOLS_BAR_HIGH;
184 }
185 NOTREACHED();
186 return 0;
187 }
188