OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "ui/views/controls/progress_bar.h" | 5 #include "ui/views/controls/progress_bar.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 #include <string> | 8 #include <string> |
9 | 9 |
10 #include "base/logging.h" | 10 #include "base/logging.h" |
11 #include "base/macros.h" | 11 #include "base/macros.h" |
12 #include "third_party/skia/include/core/SkPaint.h" | 12 #include "third_party/skia/include/core/SkPaint.h" |
13 #include "third_party/skia/include/core/SkPath.h" | 13 #include "third_party/skia/include/core/SkPath.h" |
14 #include "third_party/skia/include/core/SkXfermode.h" | 14 #include "third_party/skia/include/core/SkXfermode.h" |
15 #include "third_party/skia/include/effects/SkGradientShader.h" | 15 #include "third_party/skia/include/effects/SkGradientShader.h" |
16 #include "ui/accessibility/ax_view_state.h" | 16 #include "ui/accessibility/ax_view_state.h" |
| 17 #include "ui/gfx/animation/linear_animation.h" |
17 #include "ui/gfx/canvas.h" | 18 #include "ui/gfx/canvas.h" |
18 | 19 #include "ui/gfx/color_utils.h" |
19 namespace { | 20 #include "ui/native_theme/native_theme.h" |
20 | |
21 // Progress bar's border width. | |
22 const int kBorderWidth = 1; | |
23 | |
24 // Corner radius for the progress bar's border. | |
25 const int kCornerRadius = 2; | |
26 | |
27 // The width of the highlight at the right of the progress bar. | |
28 const int kHighlightWidth = 18; | |
29 | |
30 const SkColor kBackgroundColor = SkColorSetRGB(230, 230, 230); | |
31 const SkColor kBackgroundBorderColor = SkColorSetRGB(208, 208, 208); | |
32 const SkColor kBarBorderColor = SkColorSetRGB(65, 137, 237); | |
33 const SkColor kBarTopColor = SkColorSetRGB(110, 188, 249); | |
34 const SkColor kBarColorStart = SkColorSetRGB(86, 167, 247); | |
35 const SkColor kBarColorEnd = SkColorSetRGB(76, 148, 245); | |
36 const SkColor kBarHighlightEnd = SkColorSetRGB(114, 206, 251); | |
37 const SkColor kDisabledBarBorderColor = SkColorSetRGB(191, 191, 191); | |
38 const SkColor kDisabledBarColorStart = SkColorSetRGB(224, 224, 224); | |
39 const SkColor kDisabledBarColorEnd = SkColorSetRGB(212, 212, 212); | |
40 | |
41 void AddRoundRectPathWithPadding(int x, int y, | |
42 int w, int h, | |
43 int corner_radius, | |
44 SkScalar padding, | |
45 SkPath* path) { | |
46 DCHECK(path); | |
47 SkRect rect; | |
48 rect.set( | |
49 SkIntToScalar(x) + padding, SkIntToScalar(y) + padding, | |
50 SkIntToScalar(x + w) - padding, SkIntToScalar(y + h) - padding); | |
51 path->addRoundRect( | |
52 rect, | |
53 SkIntToScalar(corner_radius) - padding, | |
54 SkIntToScalar(corner_radius) - padding); | |
55 } | |
56 | |
57 void AddRoundRectPath(int x, int y, | |
58 int w, int h, | |
59 int corner_radius, | |
60 SkPath* path) { | |
61 AddRoundRectPathWithPadding(x, y, w, h, corner_radius, SK_ScalarHalf, path); | |
62 } | |
63 | |
64 void FillRoundRect(gfx::Canvas* canvas, | |
65 int x, int y, | |
66 int w, int h, | |
67 int corner_radius, | |
68 const SkColor colors[], | |
69 const SkScalar points[], | |
70 int count, | |
71 bool gradient_horizontal) { | |
72 SkPath path; | |
73 AddRoundRectPath(x, y, w, h, corner_radius, &path); | |
74 SkPaint paint; | |
75 paint.setStyle(SkPaint::kFill_Style); | |
76 paint.setFlags(SkPaint::kAntiAlias_Flag); | |
77 | |
78 SkPoint p[2]; | |
79 p[0].iset(x, y); | |
80 if (gradient_horizontal) { | |
81 p[1].iset(x + w, y); | |
82 } else { | |
83 p[1].iset(x, y + h); | |
84 } | |
85 paint.setShader(SkGradientShader::MakeLinear(p, colors, points, count, | |
86 SkShader::kClamp_TileMode)); | |
87 | |
88 canvas->DrawPath(path, paint); | |
89 } | |
90 | |
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); | |
110 } | |
111 } | |
112 | |
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); | |
128 } | |
129 | |
130 } // namespace | |
131 | 21 |
132 namespace views { | 22 namespace views { |
133 | 23 |
134 // static | 24 // static |
135 const char ProgressBar::kViewClassName[] = "ProgressBar"; | 25 const char ProgressBar::kViewClassName[] = "ProgressBar"; |
136 | 26 |
137 ProgressBar::ProgressBar() | 27 ProgressBar::ProgressBar() |
138 : min_display_value_(0.0), | 28 : min_display_value_(0.0), |
139 max_display_value_(1.0), | 29 max_display_value_(1.0), |
140 current_value_(0.0) { | 30 current_value_(0.0) { |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
178 *tooltip = tooltip_text_; | 68 *tooltip = tooltip_text_; |
179 return !tooltip_text_.empty(); | 69 return !tooltip_text_.empty(); |
180 } | 70 } |
181 | 71 |
182 void ProgressBar::GetAccessibleState(ui::AXViewState* state) { | 72 void ProgressBar::GetAccessibleState(ui::AXViewState* state) { |
183 state->role = ui::AX_ROLE_PROGRESS_INDICATOR; | 73 state->role = ui::AX_ROLE_PROGRESS_INDICATOR; |
184 state->AddStateFlag(ui::AX_STATE_READ_ONLY); | 74 state->AddStateFlag(ui::AX_STATE_READ_ONLY); |
185 } | 75 } |
186 | 76 |
187 gfx::Size ProgressBar::GetPreferredSize() const { | 77 gfx::Size ProgressBar::GetPreferredSize() const { |
188 gfx::Size pref_size(100, 11); | 78 gfx::Size pref_size(1, 2); |
189 gfx::Insets insets = GetInsets(); | 79 gfx::Insets insets = GetInsets(); |
190 pref_size.Enlarge(insets.width(), insets.height()); | 80 pref_size.Enlarge(insets.width(), insets.height()); |
191 return pref_size; | 81 return pref_size; |
192 } | 82 } |
193 | 83 |
194 const char* ProgressBar::GetClassName() const { | 84 const char* ProgressBar::GetClassName() const { |
195 return kViewClassName; | 85 return kViewClassName; |
196 } | 86 } |
197 | 87 |
198 void ProgressBar::OnPaint(gfx::Canvas* canvas) { | 88 SkColor ProgressBar::GetForegroundColor() const { |
| 89 return GetNativeTheme()->GetSystemColor( |
| 90 ui::NativeTheme::kColorId_CallToActionColor); |
| 91 } |
| 92 |
| 93 SkColor ProgressBar::GetBackgroundColor() const { |
| 94 // The default foreground is GoogleBlue500, and the default background is |
| 95 // that color but 80% lighter. |
| 96 return color_utils::BlendTowardOppositeLuma(GetForegroundColor(), 0xCC); |
| 97 } |
| 98 |
| 99 // DeterminateProgressBar ////////////////////////////////////////////////////// |
| 100 |
| 101 DeterminateProgressBar::DeterminateProgressBar() {} |
| 102 |
| 103 DeterminateProgressBar::~DeterminateProgressBar() {} |
| 104 |
| 105 bool DeterminateProgressBar::is_indeterminate() { |
| 106 return false; |
| 107 } |
| 108 |
| 109 void DeterminateProgressBar::OnPaint(gfx::Canvas* canvas) { |
199 gfx::Rect content_bounds = GetContentsBounds(); | 110 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(); | |
204 | |
205 const int progress_width = | |
206 static_cast<int>(bar_width * GetNormalizedValue() + 0.5); | |
207 | 111 |
208 // Draw background. | 112 // Draw background. |
209 FillRoundRect(canvas, | 113 SkPath background_path; |
210 bar_left, bar_top, bar_width, bar_height, | 114 background_path.addRect(gfx::RectToSkRect(content_bounds)); |
211 kCornerRadius, | 115 SkPaint background_paint; |
212 kBackgroundColor, kBackgroundColor, | 116 background_paint.setStyle(SkPaint::kFill_Style); |
213 false); | 117 background_paint.setFlags(SkPaint::kAntiAlias_Flag); |
214 StrokeRoundRect(canvas, | 118 background_paint.setColor(GetBackgroundColor()); |
215 bar_left, bar_top, | 119 canvas->DrawPath(background_path, background_paint); |
216 bar_width, bar_height, | |
217 kCornerRadius, | |
218 kBackgroundBorderColor, | |
219 kBorderWidth); | |
220 | 120 |
221 if (progress_width > 1) { | 121 // Draw slice. |
222 // Draw inner if wide enough. | 122 SkPath slice_path; |
223 if (progress_width > kBorderWidth * 2) { | 123 const int slice_width = |
224 canvas->Save(); | 124 static_cast<int>(content_bounds.width() * GetNormalizedValue() + 0.5); |
| 125 if (slice_width < 1) |
| 126 return; |
225 | 127 |
226 SkPath inner_path; | 128 gfx::Rect slice_bounds = content_bounds; |
227 AddRoundRectPathWithPadding( | 129 slice_bounds.set_width(slice_width); |
228 bar_left, bar_top, progress_width, bar_height, | 130 slice_path.addRect(gfx::RectToSkRect(slice_bounds)); |
229 kCornerRadius, | |
230 0, | |
231 &inner_path); | |
232 canvas->ClipPath(inner_path, false); | |
233 | 131 |
234 const SkColor bar_colors[] = { | 132 SkPaint slice_paint; |
235 kBarTopColor, | 133 slice_paint.setStyle(SkPaint::kFill_Style); |
236 kBarTopColor, | 134 slice_paint.setFlags(SkPaint::kAntiAlias_Flag); |
237 kBarColorStart, | 135 slice_paint.setColor(GetForegroundColor()); |
238 kBarColorEnd, | 136 canvas->DrawPath(slice_path, slice_paint); |
239 kBarColorEnd, | 137 } |
240 }; | |
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[] = { | |
246 0, | |
247 border_width, | |
248 border_width + highlight_width, | |
249 SK_Scalar1 - border_width, | |
250 SK_Scalar1, | |
251 }; | |
252 | 138 |
253 const SkColor disabled_bar_colors[] = { | 139 // IndeterminateProgressBar //////////////////////////////////////////////////// |
254 kDisabledBarColorStart, | |
255 kDisabledBarColorStart, | |
256 kDisabledBarColorEnd, | |
257 kDisabledBarColorEnd, | |
258 }; | |
259 | 140 |
260 const SkScalar disabled_bar_points[] = { | 141 IndeterminateProgressBar::IndeterminateProgressBar() { |
261 0, | 142 indeterminate_bar_animation_.reset(new gfx::LinearAnimation(this)); |
262 border_width, | 143 indeterminate_bar_animation_->SetDuration(2000); // In milliseconds. |
263 SK_Scalar1 - border_width, | 144 indeterminate_bar_animation_->Start(); |
264 SK_Scalar1 | 145 } |
265 }; | |
266 | 146 |
267 // Do not start from (kBorderWidth, kBorderWidth) because it makes gaps | 147 IndeterminateProgressBar::~IndeterminateProgressBar() { |
268 // between the inner and the border. | 148 indeterminate_bar_animation_->Stop(); // Just in case. |
269 FillRoundRect(canvas, | 149 } |
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); | |
278 | 150 |
279 if (enabled()) { | 151 bool IndeterminateProgressBar::is_indeterminate() { |
280 // Draw the highlight to the right. | 152 return true; |
281 const SkColor highlight_colors[] = { | 153 } |
282 SkColorSetA(kBarHighlightEnd, 0), | |
283 kBarHighlightEnd, | |
284 kBarHighlightEnd, | |
285 }; | |
286 const SkScalar highlight_points[] = { | |
287 0, SK_Scalar1 - kBorderWidth / scalar_height, SK_Scalar1, | |
288 }; | |
289 SkPaint paint; | |
290 paint.setStyle(SkPaint::kFill_Style); | |
291 paint.setFlags(SkPaint::kAntiAlias_Flag); | |
292 | 154 |
293 SkPoint p[2]; | 155 void IndeterminateProgressBar::OnPaint(gfx::Canvas* canvas) { |
294 int highlight_left = | 156 gfx::Rect content_bounds = GetContentsBounds(); |
295 std::max(0, progress_width - kHighlightWidth - kBorderWidth); | |
296 p[0].iset(highlight_left, 0); | |
297 p[1].iset(progress_width, 0); | |
298 paint.setShader(SkGradientShader::MakeLinear( | |
299 p, highlight_colors, highlight_points, arraysize(highlight_colors), | |
300 SkShader::kClamp_TileMode)); | |
301 paint.setXfermodeMode(SkXfermode::kSrcOver_Mode); | |
302 canvas->DrawRect(gfx::Rect(highlight_left, 0, | |
303 kHighlightWidth + kBorderWidth, bar_height), | |
304 paint); | |
305 } | |
306 | 157 |
307 canvas->Restore(); | 158 // Draw background. |
308 } | 159 SkPath background_path; |
| 160 background_path.addRect(gfx::RectToSkRect(content_bounds)); |
| 161 SkPaint background_paint; |
| 162 background_paint.setStyle(SkPaint::kFill_Style); |
| 163 background_paint.setFlags(SkPaint::kAntiAlias_Flag); |
| 164 background_paint.setColor(GetBackgroundColor()); |
| 165 canvas->DrawPath(background_path, background_paint); |
309 | 166 |
310 // Draw bar stroke | 167 // Draw slice. |
311 StrokeRoundRect(canvas, | 168 SkPath slice_path; |
312 bar_left, bar_top, progress_width, bar_height, | 169 double time = indeterminate_bar_animation_->GetCurrentValue(); |
313 kCornerRadius, | 170 |
314 enabled() ? kBarBorderColor : kDisabledBarBorderColor, | 171 // The animation spec corresponds to the material design lite's parameter. |
315 kBorderWidth); | 172 // (cf. https://github.com/google/material-design-lite/) |
| 173 double bar1_left; |
| 174 double bar1_width; |
| 175 double bar2_left; |
| 176 double bar2_width; |
| 177 if (time < 0.50) { |
| 178 bar1_left = time / 2; |
| 179 bar1_width = time * 1.5; |
| 180 bar2_left = 0; |
| 181 bar2_width = 0; |
| 182 } else if (time < 0.75) { |
| 183 bar1_left = time * 3 - 1.25; |
| 184 bar1_width = 0.75 - (time - 0.5) * 3; |
| 185 bar2_left = 0; |
| 186 bar2_width = time - 0.5; |
| 187 } else { |
| 188 bar1_left = 1; |
| 189 bar1_width = 0; |
| 190 bar2_left = (time - 0.75) * 4; |
| 191 bar2_width = 0.25 - (time - 0.75); |
| 192 } |
| 193 |
| 194 int bar1_x = static_cast<int>(content_bounds.width() * bar1_left); |
| 195 int bar1_w = |
| 196 std::min(static_cast<int>(content_bounds.width() * bar1_width + 0.5), |
| 197 content_bounds.width() - bar1_x); |
| 198 int bar2_x = static_cast<int>(content_bounds.width() * bar2_left); |
| 199 int bar2_w = |
| 200 std::min(static_cast<int>(content_bounds.width() * bar2_width + 0.5), |
| 201 content_bounds.width() - bar2_x); |
| 202 |
| 203 gfx::Rect slice_bounds = content_bounds; |
| 204 slice_bounds.set_x(content_bounds.x() + bar1_x); |
| 205 slice_bounds.set_width(bar1_w); |
| 206 slice_path.addRect(gfx::RectToSkRect(slice_bounds)); |
| 207 slice_bounds.set_x(content_bounds.x() + bar2_x); |
| 208 slice_bounds.set_width(bar2_w); |
| 209 slice_path.addRect(gfx::RectToSkRect(slice_bounds)); |
| 210 |
| 211 SkPaint slice_paint; |
| 212 slice_paint.setStyle(SkPaint::kFill_Style); |
| 213 slice_paint.setFlags(SkPaint::kAntiAlias_Flag); |
| 214 slice_paint.setColor(GetForegroundColor()); |
| 215 canvas->DrawPath(slice_path, slice_paint); |
| 216 } |
| 217 |
| 218 void IndeterminateProgressBar::AnimationProgressed( |
| 219 const gfx::Animation* animation) { |
| 220 if (animation == indeterminate_bar_animation_.get()) { |
| 221 DCHECK(indeterminate_bar_animation_); |
| 222 SchedulePaint(); |
316 } | 223 } |
317 } | 224 } |
318 | 225 |
| 226 void IndeterminateProgressBar::AnimationEnded(const gfx::Animation* animation) { |
| 227 // Restarts animation. |
| 228 if (animation == indeterminate_bar_animation_.get()) { |
| 229 DCHECK(indeterminate_bar_animation_); |
| 230 indeterminate_bar_animation_->Start(); |
| 231 } |
| 232 } |
| 233 |
319 } // namespace views | 234 } // namespace views |
OLD | NEW |