| OLD | NEW |
| (Empty) |
| 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. | |
| 4 | |
| 5 #include "ui/views/controls/progress_bar.h" | |
| 6 | |
| 7 #include <algorithm> | |
| 8 #include <string> | |
| 9 | |
| 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" | |
| 16 | |
| 17 namespace { | |
| 18 | |
| 19 // Progress bar's border width. | |
| 20 const int kBorderWidth = 1; | |
| 21 | |
| 22 // Corner radius for the progress bar's border. | |
| 23 const int kCornerRadius = 2; | |
| 24 | |
| 25 // The width of the highlight at the right of the progress bar. | |
| 26 const int kHighlightWidth = 18; | |
| 27 | |
| 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); | |
| 38 | |
| 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); | |
| 53 } | |
| 54 | |
| 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); | |
| 60 } | |
| 61 | |
| 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); | |
| 75 | |
| 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); | |
| 82 } | |
| 83 skia::RefPtr<SkShader> s = skia::AdoptRef(SkGradientShader::CreateLinear( | |
| 84 p, colors, points, count, SkShader::kClamp_TileMode)); | |
| 85 paint.setShader(s.get()); | |
| 86 | |
| 87 canvas->DrawPath(path, paint); | |
| 88 } | |
| 89 | |
| 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); | |
| 109 } | |
| 110 } | |
| 111 | |
| 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); | |
| 127 } | |
| 128 | |
| 129 } // namespace | |
| 130 | |
| 131 namespace views { | |
| 132 | |
| 133 // static | |
| 134 const char ProgressBar::kViewClassName[] = "ProgressBar"; | |
| 135 | |
| 136 ProgressBar::ProgressBar() | |
| 137 : min_display_value_(0.0), | |
| 138 max_display_value_(1.0), | |
| 139 current_value_(0.0) { | |
| 140 } | |
| 141 | |
| 142 ProgressBar::~ProgressBar() { | |
| 143 } | |
| 144 | |
| 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_); | |
| 150 } | |
| 151 | |
| 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(); | |
| 160 } | |
| 161 } | |
| 162 | |
| 163 void ProgressBar::SetValue(double value) { | |
| 164 if (value != current_value_) { | |
| 165 current_value_ = value; | |
| 166 SchedulePaint(); | |
| 167 } | |
| 168 } | |
| 169 | |
| 170 void ProgressBar::SetTooltipText(const base::string16& tooltip_text) { | |
| 171 tooltip_text_ = tooltip_text; | |
| 172 } | |
| 173 | |
| 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(); | |
| 179 } | |
| 180 | |
| 181 void ProgressBar::GetAccessibleState(ui::AXViewState* state) { | |
| 182 state->role = ui::AX_ROLE_PROGRESS_INDICATOR; | |
| 183 state->AddStateFlag(ui::AX_STATE_READ_ONLY); | |
| 184 } | |
| 185 | |
| 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; | |
| 191 } | |
| 192 | |
| 193 const char* ProgressBar::GetClassName() const { | |
| 194 return kViewClassName; | |
| 195 } | |
| 196 | |
| 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(); | |
| 203 | |
| 204 const int progress_width = | |
| 205 static_cast<int>(bar_width * GetNormalizedValue() + 0.5); | |
| 206 | |
| 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); | |
| 219 | |
| 220 if (progress_width > 1) { | |
| 221 // Draw inner if wide enough. | |
| 222 if (progress_width > kBorderWidth * 2) { | |
| 223 canvas->Save(); | |
| 224 | |
| 225 SkPath inner_path; | |
| 226 AddRoundRectPathWithPadding( | |
| 227 bar_left, bar_top, progress_width, bar_height, | |
| 228 kCornerRadius, | |
| 229 0, | |
| 230 &inner_path); | |
| 231 canvas->ClipPath(inner_path, false); | |
| 232 | |
| 233 const SkColor bar_colors[] = { | |
| 234 kBarTopColor, | |
| 235 kBarTopColor, | |
| 236 kBarColorStart, | |
| 237 kBarColorEnd, | |
| 238 kBarColorEnd, | |
| 239 }; | |
| 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), | |
| 244 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 | |
| 253 const SkColor disabled_bar_colors[] = { | |
| 254 kDisabledBarColorStart, | |
| 255 kDisabledBarColorStart, | |
| 256 kDisabledBarColorEnd, | |
| 257 kDisabledBarColorEnd, | |
| 258 }; | |
| 259 | |
| 260 const SkScalar disabled_bar_points[] = { | |
| 261 0, | |
| 262 border_width, | |
| 263 SK_Scalar1 - border_width, | |
| 264 SK_Scalar1 | |
| 265 }; | |
| 266 | |
| 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); | |
| 278 | |
| 279 if (enabled()) { | |
| 280 // Draw the highlight to the right. | |
| 281 const SkColor highlight_colors[] = { | |
| 282 SkColorSetA(kBarHighlightEnd, 0), | |
| 283 kBarHighlightEnd, | |
| 284 kBarHighlightEnd, | |
| 285 }; | |
| 286 const SkScalar highlight_points[] = { | |
| 287 0, | |
| 288 SK_Scalar1 - SkScalarDiv(SkIntToScalar(kBorderWidth), scalar_height), | |
| 289 SK_Scalar1, | |
| 290 }; | |
| 291 SkPaint paint; | |
| 292 paint.setStyle(SkPaint::kFill_Style); | |
| 293 paint.setFlags(SkPaint::kAntiAlias_Flag); | |
| 294 | |
| 295 SkPoint p[2]; | |
| 296 int highlight_left = | |
| 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), | |
| 308 paint); | |
| 309 } | |
| 310 | |
| 311 canvas->Restore(); | |
| 312 } | |
| 313 | |
| 314 // Draw bar stroke | |
| 315 StrokeRoundRect(canvas, | |
| 316 bar_left, bar_top, progress_width, bar_height, | |
| 317 kCornerRadius, | |
| 318 enabled() ? kBarBorderColor : kDisabledBarBorderColor, | |
| 319 kBorderWidth); | |
| 320 } | |
| 321 } | |
| 322 | |
| 323 } // namespace views | |
| OLD | NEW |