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