Pin Chrome's shortcut to the Win10 Start menu on install and OS upgrade.
[chromium-blink-merge.git] / ui / views / controls / progress_bar.cc
blobd8fe31fab5b5388c1b8761ffc8205a1408739ae2
1 // Copyright (c) 2012 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.
5 #include "ui/views/controls/progress_bar.h"
7 #include <algorithm>
8 #include <string>
10 #include "base/logging.h"
11 #include "third_party/skia/include/core/SkPaint.h"
12 #include "third_party/skia/include/core/SkXfermode.h"
13 #include "third_party/skia/include/effects/SkGradientShader.h"
14 #include "ui/accessibility/ax_view_state.h"
15 #include "ui/gfx/canvas.h"
17 namespace {
19 // Progress bar's border width.
20 const int kBorderWidth = 1;
22 // Corner radius for the progress bar's border.
23 const int kCornerRadius = 2;
25 // The width of the highlight at the right of the progress bar.
26 const int kHighlightWidth = 18;
28 const SkColor kBackgroundColor = SkColorSetRGB(230, 230, 230);
29 const SkColor kBackgroundBorderColor = SkColorSetRGB(208, 208, 208);
30 const SkColor kBarBorderColor = SkColorSetRGB(65, 137, 237);
31 const SkColor kBarTopColor = SkColorSetRGB(110, 188, 249);
32 const SkColor kBarColorStart = SkColorSetRGB(86, 167, 247);
33 const SkColor kBarColorEnd = SkColorSetRGB(76, 148, 245);
34 const SkColor kBarHighlightEnd = SkColorSetRGB(114, 206, 251);
35 const SkColor kDisabledBarBorderColor = SkColorSetRGB(191, 191, 191);
36 const SkColor kDisabledBarColorStart = SkColorSetRGB(224, 224, 224);
37 const SkColor kDisabledBarColorEnd = SkColorSetRGB(212, 212, 212);
39 void AddRoundRectPathWithPadding(int x, int y,
40 int w, int h,
41 int corner_radius,
42 SkScalar padding,
43 SkPath* path) {
44 DCHECK(path);
45 SkRect rect;
46 rect.set(
47 SkIntToScalar(x) + padding, SkIntToScalar(y) + padding,
48 SkIntToScalar(x + w) - padding, SkIntToScalar(y + h) - padding);
49 path->addRoundRect(
50 rect,
51 SkIntToScalar(corner_radius) - padding,
52 SkIntToScalar(corner_radius) - padding);
55 void AddRoundRectPath(int x, int y,
56 int w, int h,
57 int corner_radius,
58 SkPath* path) {
59 AddRoundRectPathWithPadding(x, y, w, h, corner_radius, SK_ScalarHalf, path);
62 void FillRoundRect(gfx::Canvas* canvas,
63 int x, int y,
64 int w, int h,
65 int corner_radius,
66 const SkColor colors[],
67 const SkScalar points[],
68 int count,
69 bool gradient_horizontal) {
70 SkPath path;
71 AddRoundRectPath(x, y, w, h, corner_radius, &path);
72 SkPaint paint;
73 paint.setStyle(SkPaint::kFill_Style);
74 paint.setFlags(SkPaint::kAntiAlias_Flag);
76 SkPoint p[2];
77 p[0].iset(x, y);
78 if (gradient_horizontal) {
79 p[1].iset(x + w, y);
80 } else {
81 p[1].iset(x, y + h);
83 skia::RefPtr<SkShader> s = skia::AdoptRef(SkGradientShader::CreateLinear(
84 p, colors, points, count, SkShader::kClamp_TileMode));
85 paint.setShader(s.get());
87 canvas->DrawPath(path, paint);
90 void FillRoundRect(gfx::Canvas* canvas,
91 int x, int y,
92 int w, int h,
93 int corner_radius,
94 SkColor gradient_start_color,
95 SkColor gradient_end_color,
96 bool gradient_horizontal) {
97 if (gradient_start_color != gradient_end_color) {
98 SkColor colors[2] = { gradient_start_color, gradient_end_color };
99 FillRoundRect(canvas, x, y, w, h, corner_radius,
100 colors, NULL, 2, gradient_horizontal);
101 } else {
102 SkPath path;
103 AddRoundRectPath(x, y, w, h, corner_radius, &path);
104 SkPaint paint;
105 paint.setStyle(SkPaint::kFill_Style);
106 paint.setFlags(SkPaint::kAntiAlias_Flag);
107 paint.setColor(gradient_start_color);
108 canvas->DrawPath(path, paint);
112 void StrokeRoundRect(gfx::Canvas* canvas,
113 int x, int y,
114 int w, int h,
115 int corner_radius,
116 SkColor stroke_color,
117 int stroke_width) {
118 SkPath path;
119 AddRoundRectPath(x, y, w, h, corner_radius, &path);
120 SkPaint paint;
121 paint.setShader(NULL);
122 paint.setColor(stroke_color);
123 paint.setStyle(SkPaint::kStroke_Style);
124 paint.setFlags(SkPaint::kAntiAlias_Flag);
125 paint.setStrokeWidth(SkIntToScalar(stroke_width));
126 canvas->DrawPath(path, paint);
129 } // namespace
131 namespace views {
133 // static
134 const char ProgressBar::kViewClassName[] = "ProgressBar";
136 ProgressBar::ProgressBar()
137 : min_display_value_(0.0),
138 max_display_value_(1.0),
139 current_value_(0.0) {
142 ProgressBar::~ProgressBar() {
145 double ProgressBar::GetNormalizedValue() const {
146 const double capped_value = std::min(
147 std::max(current_value_, min_display_value_), max_display_value_);
148 return (capped_value - min_display_value_) /
149 (max_display_value_ - min_display_value_);
152 void ProgressBar::SetDisplayRange(double min_display_value,
153 double max_display_value) {
154 if (min_display_value != min_display_value_ ||
155 max_display_value != max_display_value_) {
156 DCHECK(min_display_value < max_display_value);
157 min_display_value_ = min_display_value;
158 max_display_value_ = max_display_value;
159 SchedulePaint();
163 void ProgressBar::SetValue(double value) {
164 if (value != current_value_) {
165 current_value_ = value;
166 SchedulePaint();
170 void ProgressBar::SetTooltipText(const base::string16& tooltip_text) {
171 tooltip_text_ = tooltip_text;
174 bool ProgressBar::GetTooltipText(const gfx::Point& p,
175 base::string16* tooltip) const {
176 DCHECK(tooltip);
177 *tooltip = tooltip_text_;
178 return !tooltip_text_.empty();
181 void ProgressBar::GetAccessibleState(ui::AXViewState* state) {
182 state->role = ui::AX_ROLE_PROGRESS_INDICATOR;
183 state->AddStateFlag(ui::AX_STATE_READ_ONLY);
186 gfx::Size ProgressBar::GetPreferredSize() const {
187 gfx::Size pref_size(100, 11);
188 gfx::Insets insets = GetInsets();
189 pref_size.Enlarge(insets.width(), insets.height());
190 return pref_size;
193 const char* ProgressBar::GetClassName() const {
194 return kViewClassName;
197 void ProgressBar::OnPaint(gfx::Canvas* canvas) {
198 gfx::Rect content_bounds = GetContentsBounds();
199 int bar_left = content_bounds.x();
200 int bar_top = content_bounds.y();
201 int bar_width = content_bounds.width();
202 int bar_height = content_bounds.height();
204 const int progress_width =
205 static_cast<int>(bar_width * GetNormalizedValue() + 0.5);
207 // Draw background.
208 FillRoundRect(canvas,
209 bar_left, bar_top, bar_width, bar_height,
210 kCornerRadius,
211 kBackgroundColor, kBackgroundColor,
212 false);
213 StrokeRoundRect(canvas,
214 bar_left, bar_top,
215 bar_width, bar_height,
216 kCornerRadius,
217 kBackgroundBorderColor,
218 kBorderWidth);
220 if (progress_width > 1) {
221 // Draw inner if wide enough.
222 if (progress_width > kBorderWidth * 2) {
223 canvas->Save();
225 SkPath inner_path;
226 AddRoundRectPathWithPadding(
227 bar_left, bar_top, progress_width, bar_height,
228 kCornerRadius,
230 &inner_path);
231 canvas->ClipPath(inner_path, false);
233 const SkColor bar_colors[] = {
234 kBarTopColor,
235 kBarTopColor,
236 kBarColorStart,
237 kBarColorEnd,
238 kBarColorEnd,
240 // We want a thin 1-pixel line for kBarTopColor.
241 SkScalar scalar_height = SkIntToScalar(bar_height);
242 SkScalar highlight_width = 1 / scalar_height;
243 SkScalar border_width = kBorderWidth / scalar_height;
244 const SkScalar bar_points[] = {
246 border_width,
247 border_width + highlight_width,
248 SK_Scalar1 - border_width,
249 SK_Scalar1,
252 const SkColor disabled_bar_colors[] = {
253 kDisabledBarColorStart,
254 kDisabledBarColorStart,
255 kDisabledBarColorEnd,
256 kDisabledBarColorEnd,
259 const SkScalar disabled_bar_points[] = {
261 border_width,
262 SK_Scalar1 - border_width,
263 SK_Scalar1
266 // Do not start from (kBorderWidth, kBorderWidth) because it makes gaps
267 // between the inner and the border.
268 FillRoundRect(canvas,
269 bar_left, bar_top,
270 progress_width, bar_height,
271 kCornerRadius,
272 enabled() ? bar_colors : disabled_bar_colors,
273 enabled() ? bar_points : disabled_bar_points,
274 enabled() ? arraysize(bar_colors) :
275 arraysize(disabled_bar_colors),
276 false);
278 if (enabled()) {
279 // Draw the highlight to the right.
280 const SkColor highlight_colors[] = {
281 SkColorSetA(kBarHighlightEnd, 0),
282 kBarHighlightEnd,
283 kBarHighlightEnd,
285 const SkScalar highlight_points[] = {
286 0, SK_Scalar1 - kBorderWidth / scalar_height, SK_Scalar1,
288 SkPaint paint;
289 paint.setStyle(SkPaint::kFill_Style);
290 paint.setFlags(SkPaint::kAntiAlias_Flag);
292 SkPoint p[2];
293 int highlight_left =
294 std::max(0, progress_width - kHighlightWidth - kBorderWidth);
295 p[0].iset(highlight_left, 0);
296 p[1].iset(progress_width, 0);
297 skia::RefPtr<SkShader> s =
298 skia::AdoptRef(SkGradientShader::CreateLinear(
299 p, highlight_colors, highlight_points,
300 arraysize(highlight_colors), SkShader::kClamp_TileMode));
301 paint.setShader(s.get());
302 paint.setXfermodeMode(SkXfermode::kSrcOver_Mode);
303 canvas->DrawRect(gfx::Rect(highlight_left, 0,
304 kHighlightWidth + kBorderWidth, bar_height),
305 paint);
308 canvas->Restore();
311 // Draw bar stroke
312 StrokeRoundRect(canvas,
313 bar_left, bar_top, progress_width, bar_height,
314 kCornerRadius,
315 enabled() ? kBarBorderColor : kDisabledBarBorderColor,
316 kBorderWidth);
320 } // namespace views