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 <algorithm>
      8 
      9 #include "grit/theme_resources.h"
     10 #include "ui/base/theme_provider.h"
     11 #include "ui/gfx/animation/multi_animation.h"
     12 #include "ui/gfx/canvas.h"
     13 #include "ui/gfx/image/image_skia.h"
     14 #include "ui/gfx/rect.h"
     15 
     16 namespace {
     17 
     18 // The wrench icon is made up of this many bars stacked vertically.
     19 const int kBarCount = 3;
     20 
     21 // |value| is the animation progress from 0 to 1. |index| is the index of the
     22 // bar being drawn. This function returns a new progress value (from 0 to 1)
     23 // such that bars appear staggered.
     24 double GetStaggeredValue(double value, int index) {
     25   // When animating the wrench icon's bars the bars are staggered by this
     26   // factor.
     27   const double kStaggerFactor = 0.15;
     28   double maxStaggeredValue = 1.0 - (kBarCount - 1) * kStaggerFactor;
     29   double staggeredValue = (value - kStaggerFactor * index) / maxStaggeredValue;
     30   return std::min(1.0, std::max(0.0, staggeredValue));
     31 }
     32 
     33 }  // namespace
     34 
     35 WrenchIconPainter::WrenchIconPainter(Delegate* delegate)
     36     : delegate_(delegate),
     37       severity_(SEVERITY_NONE) {
     38 }
     39 
     40 WrenchIconPainter::~WrenchIconPainter() {}
     41 
     42 void WrenchIconPainter::SetSeverity(Severity severity, bool animate) {
     43   if (severity_ == severity)
     44     return;
     45 
     46   severity_ = severity;
     47   delegate_->ScheduleWrenchIconPaint();
     48   animation_.reset();
     49   if (severity_ == SEVERITY_NONE || !animate)
     50     return;
     51 
     52   gfx::MultiAnimation::Parts parts;
     53   // Animate the bars left to right.
     54   parts.push_back(gfx::MultiAnimation::Part(1300, gfx::Tween::LINEAR));
     55   // Fade out animation.
     56   parts.push_back(gfx::MultiAnimation::Part(1000, gfx::Tween::EASE_IN));
     57   // Again, animate the bars left to right.
     58   parts.push_back(gfx::MultiAnimation::Part(1300, gfx::Tween::LINEAR));
     59 
     60   animation_.reset(
     61       new gfx::MultiAnimation(parts, base::TimeDelta::FromMilliseconds(40)));
     62   animation_->set_delegate(this);
     63   animation_->set_continuous(false);
     64   animation_->Start();
     65 }
     66 
     67 void WrenchIconPainter::Paint(gfx::Canvas* canvas,
     68                               ui::ThemeProvider* theme_provider,
     69                               const gfx::Rect& rect,
     70                               BezelType bezel_type) {
     71   gfx::Point center = rect.CenterPoint();
     72 
     73   // Bezel.
     74   if (bezel_type != BEZEL_NONE) {
     75     gfx::ImageSkia* image = theme_provider->GetImageSkiaNamed(
     76         bezel_type == BEZEL_HOVER ? IDR_TOOLBAR_BEZEL_HOVER
     77                                   : IDR_TOOLBAR_BEZEL_PRESSED);
     78     canvas->DrawImageInt(*image,
     79                          center.x() - image->width() / 2,
     80                          center.y() - image->height() / 2);
     81   }
     82 
     83   // The bars with no color.
     84   {
     85     gfx::ImageSkia* image = theme_provider->GetImageSkiaNamed(IDR_TOOLS_BAR);
     86     int x = center.x() - image->width() / 2;
     87     int y = center.y() - image->height() * kBarCount / 2;
     88     for (int i = 0; i < kBarCount; ++i) {
     89       canvas->DrawImageInt(*image, x, y);
     90       y += image->height();
     91     }
     92   }
     93 
     94   // The bars with color based on severity.
     95   int severity_image_id = GetCurrentSeverityImageID();
     96   if (severity_image_id) {
     97     gfx::ImageSkia* image =
     98         theme_provider->GetImageSkiaNamed(severity_image_id);
     99     int x = center.x() - image->width() / 2;
    100     int y = center.y() - image->height() * kBarCount / 2;
    101     for (int i = 0; i < kBarCount; ++i) {
    102       SkPaint paint;
    103       int width = image->width();
    104 
    105       if (animation_ && animation_->is_animating()) {
    106         if (animation_->current_part_index() % 2 == 1) {
    107           // Fade out.
    108           int alpha = animation_->CurrentValueBetween(0xFF, 0);
    109           if (alpha == 0)
    110             continue;
    111           paint.setAlpha(alpha);
    112         } else {
    113           // Stagger the widths.
    114           width = image->width() *
    115                   GetStaggeredValue(animation_->GetCurrentValue(), i);
    116           if (width == 0)
    117             continue;
    118         }
    119       }
    120 
    121       canvas->DrawImageInt(*image, 0, 0, width, image->height(),
    122                             x, y, width, image->height(), false, paint);
    123       y += image->height();
    124     }
    125   }
    126 
    127   if (!badge_.isNull())
    128     canvas->DrawImageInt(badge_, 0, 0);
    129 }
    130 
    131 void WrenchIconPainter::AnimationProgressed(const gfx::Animation* animation) {
    132   delegate_->ScheduleWrenchIconPaint();
    133 }
    134 
    135 int WrenchIconPainter::GetCurrentSeverityImageID() const {
    136   switch (severity_) {
    137     case SEVERITY_NONE:
    138       return 0;
    139     case SEVERITY_LOW:
    140       return IDR_TOOLS_BAR_LOW;
    141     case SEVERITY_MEDIUM:
    142       return IDR_TOOLS_BAR_MEDIUM;
    143     case SEVERITY_HIGH:
    144       return IDR_TOOLS_BAR_HIGH;
    145   }
    146   NOTREACHED();
    147   return 0;
    148 }
    149