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