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/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"
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
,
47 SkIntToScalar(x
) + padding
, SkIntToScalar(y
) + padding
,
48 SkIntToScalar(x
+ w
) - padding
, SkIntToScalar(y
+ h
) - padding
);
51 SkIntToScalar(corner_radius
) - padding
,
52 SkIntToScalar(corner_radius
) - padding
);
55 void AddRoundRectPath(int x
, int y
,
59 AddRoundRectPathWithPadding(x
, y
, w
, h
, corner_radius
, SK_ScalarHalf
, path
);
62 void FillRoundRect(gfx::Canvas
* canvas
,
66 const SkColor colors
[],
67 const SkScalar points
[],
69 bool gradient_horizontal
) {
71 AddRoundRectPath(x
, y
, w
, h
, corner_radius
, &path
);
73 paint
.setStyle(SkPaint::kFill_Style
);
74 paint
.setFlags(SkPaint::kAntiAlias_Flag
);
78 if (gradient_horizontal
) {
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
,
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
);
103 AddRoundRectPath(x
, y
, w
, h
, corner_radius
, &path
);
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
,
116 SkColor stroke_color
,
119 AddRoundRectPath(x
, y
, w
, h
, corner_radius
, &path
);
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
);
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
;
163 void ProgressBar::SetValue(double value
) {
164 if (value
!= current_value_
) {
165 current_value_
= value
;
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 {
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());
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);
208 FillRoundRect(canvas
,
209 bar_left
, bar_top
, bar_width
, bar_height
,
211 kBackgroundColor
, kBackgroundColor
,
213 StrokeRoundRect(canvas
,
215 bar_width
, bar_height
,
217 kBackgroundBorderColor
,
220 if (progress_width
> 1) {
221 // Draw inner if wide enough.
222 if (progress_width
> kBorderWidth
* 2) {
226 AddRoundRectPathWithPadding(
227 bar_left
, bar_top
, progress_width
, bar_height
,
231 canvas
->ClipPath(inner_path
, false);
233 const SkColor bar_colors
[] = {
240 // We want a thin 1-pixel line for kBarTopColor.
241 SkScalar scalar_height
= SkIntToScalar(bar_height
);
242 SkScalar highlight_width
= SkScalarDiv(SK_Scalar1
, scalar_height
);
243 SkScalar border_width
= SkScalarDiv(SkIntToScalar(kBorderWidth
),
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
[] = {
288 SK_Scalar1
- SkScalarDiv(SkIntToScalar(kBorderWidth
), scalar_height
),
292 paint
.setStyle(SkPaint::kFill_Style
);
293 paint
.setFlags(SkPaint::kAntiAlias_Flag
);
297 std::max(0, progress_width
- kHighlightWidth
- kBorderWidth
);
298 p
[0].iset(highlight_left
, 0);
299 p
[1].iset(progress_width
, 0);
300 skia::RefPtr
<SkShader
> s
=
301 skia::AdoptRef(SkGradientShader::CreateLinear(
302 p
, highlight_colors
, highlight_points
,
303 arraysize(highlight_colors
), SkShader::kClamp_TileMode
));
304 paint
.setShader(s
.get());
305 paint
.setXfermodeMode(SkXfermode::kSrcOver_Mode
);
306 canvas
->DrawRect(gfx::Rect(highlight_left
, 0,
307 kHighlightWidth
+ kBorderWidth
, bar_height
),
315 StrokeRoundRect(canvas
,
316 bar_left
, bar_top
, progress_width
, bar_height
,
318 enabled() ? kBarBorderColor
: kDisabledBarBorderColor
,