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"
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"
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
,
48 SkIntToScalar(x
) + padding
, SkIntToScalar(y
) + padding
,
49 SkIntToScalar(x
+ w
) - padding
, SkIntToScalar(y
+ h
) - padding
);
52 SkIntToScalar(corner_radius
) - padding
,
53 SkIntToScalar(corner_radius
) - padding
);
56 void AddRoundRectPath(int x
, int y
,
60 AddRoundRectPathWithPadding(x
, y
, w
, h
, corner_radius
, SK_ScalarHalf
, path
);
63 void FillRoundRect(gfx::Canvas
* canvas
,
67 const SkColor colors
[],
68 const SkScalar points
[],
70 bool gradient_horizontal
) {
72 AddRoundRectPath(x
, y
, w
, h
, corner_radius
, &path
);
74 paint
.setStyle(SkPaint::kFill_Style
);
75 paint
.setFlags(SkPaint::kAntiAlias_Flag
);
79 if (gradient_horizontal
) {
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
,
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
);
104 AddRoundRectPath(x
, y
, w
, h
, corner_radius
, &path
);
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
,
117 SkColor stroke_color
,
120 AddRoundRectPath(x
, y
, w
, h
, corner_radius
, &path
);
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
);
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
;
164 void ProgressBar::SetValue(double value
) {
165 if (value
!= current_value_
) {
166 current_value_
= value
;
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 {
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());
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);
209 FillRoundRect(canvas
,
210 bar_left
, bar_top
, bar_width
, bar_height
,
212 kBackgroundColor
, kBackgroundColor
,
214 StrokeRoundRect(canvas
,
216 bar_width
, bar_height
,
218 kBackgroundBorderColor
,
221 if (progress_width
> 1) {
222 // Draw inner if wide enough.
223 if (progress_width
> kBorderWidth
* 2) {
227 AddRoundRectPathWithPadding(
228 bar_left
, bar_top
, progress_width
, bar_height
,
232 canvas
->ClipPath(inner_path
, false);
234 const SkColor bar_colors
[] = {
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
[] = {
248 border_width
+ highlight_width
,
249 SK_Scalar1
- border_width
,
253 const SkColor disabled_bar_colors
[] = {
254 kDisabledBarColorStart
,
255 kDisabledBarColorStart
,
256 kDisabledBarColorEnd
,
257 kDisabledBarColorEnd
,
260 const SkScalar disabled_bar_points
[] = {
263 SK_Scalar1
- border_width
,
267 // Do not start from (kBorderWidth, kBorderWidth) because it makes gaps
268 // between the inner and the border.
269 FillRoundRect(canvas
,
271 progress_width
, bar_height
,
273 enabled() ? bar_colors
: disabled_bar_colors
,
274 enabled() ? bar_points
: disabled_bar_points
,
275 enabled() ? arraysize(bar_colors
) :
276 arraysize(disabled_bar_colors
),
280 // Draw the highlight to the right.
281 const SkColor highlight_colors
[] = {
282 SkColorSetA(kBarHighlightEnd
, 0),
286 const SkScalar highlight_points
[] = {
287 0, SK_Scalar1
- kBorderWidth
/ scalar_height
, SK_Scalar1
,
290 paint
.setStyle(SkPaint::kFill_Style
);
291 paint
.setFlags(SkPaint::kAntiAlias_Flag
);
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
),
313 StrokeRoundRect(canvas
,
314 bar_left
, bar_top
, progress_width
, bar_height
,
316 enabled() ? kBarBorderColor
: kDisabledBarBorderColor
,