Home | History | Annotate | Download | only in toolbar
      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/animation/multi_animation.h"
      9 #include "ui/base/theme_provider.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.
     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
     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
     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
     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 
     74 WrenchIconPainter::WrenchIconPainter(Delegate* delegate)
     75     : delegate_(delegate),
     76       severity_(SEVERITY_NONE) {
     77 }
     78 
     79 WrenchIconPainter::~WrenchIconPainter() {}
     80 
     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   ui::MultiAnimation::Parts parts;
     92   // Animate the bars left to right.
     93   parts.push_back(ui::MultiAnimation::Part(1300, ui::Tween::LINEAR));
     94   // Fade out animation.
     95   parts.push_back(ui::MultiAnimation::Part(1000, ui::Tween::EASE_IN));
     96   // Again, animate the bars left to right.
     97   parts.push_back(ui::MultiAnimation::Part(1300, ui::Tween::LINEAR));
     98 
     99   animation_.reset(
    100       new ui::MultiAnimation(parts, base::TimeDelta::FromMilliseconds(40)));
    101   animation_->set_delegate(this);
    102   animation_->set_continuous(false);
    103   animation_->Start();
    104 }
    105 
    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 
    170 void WrenchIconPainter::AnimationProgressed(const ui::Animation* animation) {
    171   delegate_->ScheduleWrenchIconPaint();
    172 }
    173 
    174 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