blob: 34f32b5730b8f477dc519124686347c09b733647 [file] [log] [blame]
// Copyright (c) 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/ui/toolbar/wrench_icon_painter.h"
#include "grit/theme_resources.h"
#include "ui/base/theme_provider.h"
#include "ui/gfx/animation/multi_animation.h"
#include "ui/gfx/canvas.h"
#include "ui/gfx/image/image_skia.h"
#include "ui/gfx/rect.h"
namespace {
// The wrench icon is made up of this many bars stacked vertically.
const int kBarCount = 3;
// |value| is the animation progress from 0 to 1. |index| is the index of the
// bar being drawn. This function returns a new progress value (from 0 to 1)
// such that bars appear staggered.
double GetStaggeredValue(double value, int index) {
// When animating the wrench icon's bars the bars are staggered by this
// factor.
const double kStaggerFactor = 0.15;
double maxStaggeredValue = 1.0 - (kBarCount - 1) * kStaggerFactor;
double staggeredValue = (value - kStaggerFactor * index) / maxStaggeredValue;
return std::min(1.0, std::max(0.0, staggeredValue));
}
} // namespace
// static
WrenchIconPainter::Severity WrenchIconPainter::SeverityFromUpgradeLevel(
UpgradeDetector::UpgradeNotificationAnnoyanceLevel level) {
switch (level) {
case UpgradeDetector::UPGRADE_ANNOYANCE_NONE:
return SEVERITY_NONE;
case UpgradeDetector::UPGRADE_ANNOYANCE_LOW:
return SEVERITY_LOW;
case UpgradeDetector::UPGRADE_ANNOYANCE_ELEVATED:
return SEVERITY_MEDIUM;
case UpgradeDetector::UPGRADE_ANNOYANCE_HIGH:
return SEVERITY_HIGH;
case UpgradeDetector::UPGRADE_ANNOYANCE_SEVERE:
return SEVERITY_HIGH;
case UpgradeDetector::UPGRADE_ANNOYANCE_CRITICAL:
return SEVERITY_HIGH;
}
NOTREACHED();
return SEVERITY_NONE;
}
// static
bool WrenchIconPainter::ShouldAnimateUpgradeLevel(
UpgradeDetector::UpgradeNotificationAnnoyanceLevel level) {
bool should_animate = true;
if (level == UpgradeDetector::UPGRADE_ANNOYANCE_LOW) {
// Only animate low severity upgrades once.
static bool should_animate_low_severity = true;
should_animate = should_animate_low_severity;
should_animate_low_severity = false;
}
return should_animate;
}
// static
WrenchIconPainter::Severity WrenchIconPainter::GlobalErrorSeverity() {
// If you change this make sure to also change the menu icon and the bubble
// icon.
return SEVERITY_MEDIUM;
}
WrenchIconPainter::WrenchIconPainter(Delegate* delegate)
: delegate_(delegate),
severity_(SEVERITY_NONE) {
}
WrenchIconPainter::~WrenchIconPainter() {}
void WrenchIconPainter::SetSeverity(Severity severity, bool animate) {
if (severity_ == severity)
return;
severity_ = severity;
delegate_->ScheduleWrenchIconPaint();
animation_.reset();
if (severity_ == SEVERITY_NONE || !animate)
return;
gfx::MultiAnimation::Parts parts;
// Animate the bars left to right.
parts.push_back(gfx::MultiAnimation::Part(1300, gfx::Tween::LINEAR));
// Fade out animation.
parts.push_back(gfx::MultiAnimation::Part(1000, gfx::Tween::EASE_IN));
// Again, animate the bars left to right.
parts.push_back(gfx::MultiAnimation::Part(1300, gfx::Tween::LINEAR));
animation_.reset(
new gfx::MultiAnimation(parts, base::TimeDelta::FromMilliseconds(40)));
animation_->set_delegate(this);
animation_->set_continuous(false);
animation_->Start();
}
void WrenchIconPainter::Paint(gfx::Canvas* canvas,
ui::ThemeProvider* theme_provider,
const gfx::Rect& rect,
BezelType bezel_type) {
gfx::Point center = rect.CenterPoint();
// Bezel.
if (bezel_type != BEZEL_NONE) {
gfx::ImageSkia* image = theme_provider->GetImageSkiaNamed(
bezel_type == BEZEL_HOVER ? IDR_TOOLBAR_BEZEL_HOVER
: IDR_TOOLBAR_BEZEL_PRESSED);
canvas->DrawImageInt(*image,
center.x() - image->width() / 2,
center.y() - image->height() / 2);
}
// The bars with no color.
{
gfx::ImageSkia* image = theme_provider->GetImageSkiaNamed(IDR_TOOLS_BAR);
int x = center.x() - image->width() / 2;
int y = center.y() - image->height() * kBarCount / 2;
for (int i = 0; i < kBarCount; ++i) {
canvas->DrawImageInt(*image, x, y);
y += image->height();
}
}
// The bars with color based on severity.
int severity_image_id = GetCurrentSeverityImageID();
if (severity_image_id) {
gfx::ImageSkia* image =
theme_provider->GetImageSkiaNamed(severity_image_id);
int x = center.x() - image->width() / 2;
int y = center.y() - image->height() * kBarCount / 2;
for (int i = 0; i < kBarCount; ++i) {
SkPaint paint;
int width = image->width();
if (animation_ && animation_->is_animating()) {
if (animation_->current_part_index() % 2 == 1) {
// Fade out.
int alpha = animation_->CurrentValueBetween(0xFF, 0);
if (alpha == 0)
continue;
paint.setAlpha(alpha);
} else {
// Stagger the widths.
width = image->width() *
GetStaggeredValue(animation_->GetCurrentValue(), i);
if (width == 0)
continue;
}
}
canvas->DrawImageInt(*image, 0, 0, width, image->height(),
x, y, width, image->height(), false, paint);
y += image->height();
}
}
if (!badge_.isNull())
canvas->DrawImageInt(badge_, 0, 0);
}
void WrenchIconPainter::AnimationProgressed(const gfx::Animation* animation) {
delegate_->ScheduleWrenchIconPaint();
}
int WrenchIconPainter::GetCurrentSeverityImageID() const {
switch (severity_) {
case SEVERITY_NONE:
return 0;
case SEVERITY_LOW:
return IDR_TOOLS_BAR_LOW;
case SEVERITY_MEDIUM:
return IDR_TOOLS_BAR_MEDIUM;
case SEVERITY_HIGH:
return IDR_TOOLS_BAR_HIGH;
}
NOTREACHED();
return 0;
}