Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(149)

Unified Diff: ui/views/controls/progress_bar.cc

Issue 2329633003: Implement progress bar spec (determinate and indeterminate). (Closed)
Patch Set: sky review Created 4 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: ui/views/controls/progress_bar.cc
diff --git a/ui/views/controls/progress_bar.cc b/ui/views/controls/progress_bar.cc
index 0278e5b51b0fdb0b4276b1e7c99dda704856effd..c34ac5dee555d3bceb16ff353a3602e3283569b0 100644
--- a/ui/views/controls/progress_bar.cc
+++ b/ui/views/controls/progress_bar.cc
@@ -14,306 +14,196 @@
#include "third_party/skia/include/core/SkXfermode.h"
#include "third_party/skia/include/effects/SkGradientShader.h"
#include "ui/accessibility/ax_view_state.h"
+#include "ui/gfx/animation/linear_animation.h"
#include "ui/gfx/canvas.h"
+#include "ui/gfx/color_utils.h"
+#include "ui/native_theme/native_theme.h"
-namespace {
-
-// Progress bar's border width.
-const int kBorderWidth = 1;
-
-// Corner radius for the progress bar's border.
-const int kCornerRadius = 2;
-
-// The width of the highlight at the right of the progress bar.
-const int kHighlightWidth = 18;
-
-const SkColor kBackgroundColor = SkColorSetRGB(230, 230, 230);
-const SkColor kBackgroundBorderColor = SkColorSetRGB(208, 208, 208);
-const SkColor kBarBorderColor = SkColorSetRGB(65, 137, 237);
-const SkColor kBarTopColor = SkColorSetRGB(110, 188, 249);
-const SkColor kBarColorStart = SkColorSetRGB(86, 167, 247);
-const SkColor kBarColorEnd = SkColorSetRGB(76, 148, 245);
-const SkColor kBarHighlightEnd = SkColorSetRGB(114, 206, 251);
-const SkColor kDisabledBarBorderColor = SkColorSetRGB(191, 191, 191);
-const SkColor kDisabledBarColorStart = SkColorSetRGB(224, 224, 224);
-const SkColor kDisabledBarColorEnd = SkColorSetRGB(212, 212, 212);
-
-void AddRoundRectPathWithPadding(int x, int y,
- int w, int h,
- int corner_radius,
- SkScalar padding,
- SkPath* path) {
- DCHECK(path);
- SkRect rect;
- rect.set(
- SkIntToScalar(x) + padding, SkIntToScalar(y) + padding,
- SkIntToScalar(x + w) - padding, SkIntToScalar(y + h) - padding);
- path->addRoundRect(
- rect,
- SkIntToScalar(corner_radius) - padding,
- SkIntToScalar(corner_radius) - padding);
-}
-
-void AddRoundRectPath(int x, int y,
- int w, int h,
- int corner_radius,
- SkPath* path) {
- AddRoundRectPathWithPadding(x, y, w, h, corner_radius, SK_ScalarHalf, path);
-}
+namespace views {
-void FillRoundRect(gfx::Canvas* canvas,
- int x, int y,
- int w, int h,
- int corner_radius,
- const SkColor colors[],
- const SkScalar points[],
- int count,
- bool gradient_horizontal) {
- SkPath path;
- AddRoundRectPath(x, y, w, h, corner_radius, &path);
- SkPaint paint;
- paint.setStyle(SkPaint::kFill_Style);
- paint.setFlags(SkPaint::kAntiAlias_Flag);
-
- SkPoint p[2];
- p[0].iset(x, y);
- if (gradient_horizontal) {
- p[1].iset(x + w, y);
- } else {
- p[1].iset(x, y + h);
- }
- paint.setShader(SkGradientShader::MakeLinear(p, colors, points, count,
- SkShader::kClamp_TileMode));
+namespace {
- canvas->DrawPath(path, paint);
-}
+// In DP, the amount to round the corners of the progress bar (both bg and
+// fg, aka slice).
+const int kCornerRadius = 3;
-void FillRoundRect(gfx::Canvas* canvas,
- int x, int y,
- int w, int h,
- int corner_radius,
- SkColor gradient_start_color,
- SkColor gradient_end_color,
- bool gradient_horizontal) {
- if (gradient_start_color != gradient_end_color) {
- SkColor colors[2] = { gradient_start_color, gradient_end_color };
- FillRoundRect(canvas, x, y, w, h, corner_radius,
- colors, NULL, 2, gradient_horizontal);
+// Adds a rectangle to the path. The corners will be rounded if there is room.
+void AddPossiblyRoundRectToPath(const gfx::Rect& rectangle, SkPath* path) {
+ if (rectangle.height() < kCornerRadius) {
+ path->addRect(gfx::RectToSkRect(rectangle));
} else {
- SkPath path;
- AddRoundRectPath(x, y, w, h, corner_radius, &path);
- SkPaint paint;
- paint.setStyle(SkPaint::kFill_Style);
- paint.setFlags(SkPaint::kAntiAlias_Flag);
- paint.setColor(gradient_start_color);
- canvas->DrawPath(path, paint);
+ path->addRoundRect(gfx::RectToSkRect(rectangle), kCornerRadius,
+ kCornerRadius);
}
}
-void StrokeRoundRect(gfx::Canvas* canvas,
- int x, int y,
- int w, int h,
- int corner_radius,
- SkColor stroke_color,
- int stroke_width) {
- SkPath path;
- AddRoundRectPath(x, y, w, h, corner_radius, &path);
- SkPaint paint;
- paint.setShader(NULL);
- paint.setColor(stroke_color);
- paint.setStyle(SkPaint::kStroke_Style);
- paint.setFlags(SkPaint::kAntiAlias_Flag);
- paint.setStrokeWidth(SkIntToScalar(stroke_width));
- canvas->DrawPath(path, paint);
-}
-
} // namespace
-namespace views {
-
// static
const char ProgressBar::kViewClassName[] = "ProgressBar";
-ProgressBar::ProgressBar()
- : min_display_value_(0.0),
- max_display_value_(1.0),
- current_value_(0.0) {
-}
+ProgressBar::ProgressBar(int preferred_height)
+ : preferred_height_(preferred_height) {}
ProgressBar::~ProgressBar() {
}
-double ProgressBar::GetNormalizedValue() const {
- const double capped_value = std::min(
- std::max(current_value_, min_display_value_), max_display_value_);
- return (capped_value - min_display_value_) /
- (max_display_value_ - min_display_value_);
+void ProgressBar::GetAccessibleState(ui::AXViewState* state) {
+ state->role = ui::AX_ROLE_PROGRESS_INDICATOR;
+ state->AddStateFlag(ui::AX_STATE_READ_ONLY);
}
-void ProgressBar::SetDisplayRange(double min_display_value,
- double max_display_value) {
- if (min_display_value != min_display_value_ ||
- max_display_value != max_display_value_) {
- DCHECK(min_display_value < max_display_value);
- min_display_value_ = min_display_value;
- max_display_value_ = max_display_value;
- SchedulePaint();
- }
+gfx::Size ProgressBar::GetPreferredSize() const {
+ // The width will typically be ignored.
+ gfx::Size pref_size(1, preferred_height_);
+ gfx::Insets insets = GetInsets();
+ pref_size.Enlarge(insets.width(), insets.height());
+ return pref_size;
+}
+
+const char* ProgressBar::GetClassName() const {
+ return kViewClassName;
+}
+
+void ProgressBar::OnPaint(gfx::Canvas* canvas) {
+ if (IsIndeterminate())
+ return OnPaintIndeterminate(canvas);
+
+ gfx::Rect content_bounds = GetContentsBounds();
+
+ // Draw background.
+ SkPath background_path;
+ AddPossiblyRoundRectToPath(content_bounds, &background_path);
+ SkPaint background_paint;
+ background_paint.setStyle(SkPaint::kFill_Style);
+ background_paint.setFlags(SkPaint::kAntiAlias_Flag);
+ background_paint.setColor(GetBackgroundColor());
+ canvas->DrawPath(background_path, background_paint);
+
+ // Draw slice.
+ SkPath slice_path;
+ const int slice_width = static_cast<int>(
+ content_bounds.width() * std::min(current_value_, 1.0) + 0.5);
+ if (slice_width < 1)
+ return;
+
+ gfx::Rect slice_bounds = content_bounds;
+ slice_bounds.set_width(slice_width);
+ AddPossiblyRoundRectToPath(slice_bounds, &slice_path);
+
+ SkPaint slice_paint;
+ slice_paint.setStyle(SkPaint::kFill_Style);
+ slice_paint.setFlags(SkPaint::kAntiAlias_Flag);
+ slice_paint.setColor(GetForegroundColor());
+ canvas->DrawPath(slice_path, slice_paint);
}
void ProgressBar::SetValue(double value) {
- if (value != current_value_) {
- current_value_ = value;
+ double adjusted_value = (value < 0.0 || value > 1.0) ? -1.0 : value;
+
+ if (adjusted_value == current_value_)
+ return;
+
+ current_value_ = adjusted_value;
+ if (IsIndeterminate()) {
+ indeterminate_bar_animation_.reset(new gfx::LinearAnimation(this));
+ indeterminate_bar_animation_->SetDuration(2000); // In milliseconds.
+ indeterminate_bar_animation_->Start();
+ } else {
+ indeterminate_bar_animation_.reset();
SchedulePaint();
}
}
-void ProgressBar::SetTooltipText(const base::string16& tooltip_text) {
- tooltip_text_ = tooltip_text;
+SkColor ProgressBar::GetForegroundColor() const {
+ return GetNativeTheme()->GetSystemColor(
+ ui::NativeTheme::kColorId_CallToActionColor);
}
-bool ProgressBar::GetTooltipText(const gfx::Point& p,
- base::string16* tooltip) const {
- DCHECK(tooltip);
- *tooltip = tooltip_text_;
- return !tooltip_text_.empty();
+SkColor ProgressBar::GetBackgroundColor() const {
+ // The default foreground is GoogleBlue500, and the default background is
+ // that color but 80% lighter.
+ return color_utils::BlendTowardOppositeLuma(GetForegroundColor(), 0xCC);
}
-void ProgressBar::GetAccessibleState(ui::AXViewState* state) {
- state->role = ui::AX_ROLE_PROGRESS_INDICATOR;
- state->AddStateFlag(ui::AX_STATE_READ_ONLY);
+void ProgressBar::AnimationProgressed(const gfx::Animation* animation) {
+ DCHECK_EQ(animation, indeterminate_bar_animation_.get());
+ DCHECK(IsIndeterminate());
+ SchedulePaint();
}
-gfx::Size ProgressBar::GetPreferredSize() const {
- gfx::Size pref_size(100, 11);
- gfx::Insets insets = GetInsets();
- pref_size.Enlarge(insets.width(), insets.height());
- return pref_size;
+void ProgressBar::AnimationEnded(const gfx::Animation* animation) {
+ DCHECK_EQ(animation, indeterminate_bar_animation_.get());
+ // Restarts animation.
+ if (IsIndeterminate())
+ indeterminate_bar_animation_->Start();
}
-const char* ProgressBar::GetClassName() const {
- return kViewClassName;
+bool ProgressBar::IsIndeterminate() {
+ return current_value_ < 0.0;
}
-void ProgressBar::OnPaint(gfx::Canvas* canvas) {
+void ProgressBar::OnPaintIndeterminate(gfx::Canvas* canvas) {
gfx::Rect content_bounds = GetContentsBounds();
- int bar_left = content_bounds.x();
- int bar_top = content_bounds.y();
- int bar_width = content_bounds.width();
- int bar_height = content_bounds.height();
-
- const int progress_width =
- static_cast<int>(bar_width * GetNormalizedValue() + 0.5);
// Draw background.
- FillRoundRect(canvas,
- bar_left, bar_top, bar_width, bar_height,
- kCornerRadius,
- kBackgroundColor, kBackgroundColor,
- false);
- StrokeRoundRect(canvas,
- bar_left, bar_top,
- bar_width, bar_height,
- kCornerRadius,
- kBackgroundBorderColor,
- kBorderWidth);
-
- if (progress_width > 1) {
- // Draw inner if wide enough.
- if (progress_width > kBorderWidth * 2) {
- canvas->Save();
-
- SkPath inner_path;
- AddRoundRectPathWithPadding(
- bar_left, bar_top, progress_width, bar_height,
- kCornerRadius,
- 0,
- &inner_path);
- canvas->ClipPath(inner_path, false);
-
- const SkColor bar_colors[] = {
- kBarTopColor,
- kBarTopColor,
- kBarColorStart,
- kBarColorEnd,
- kBarColorEnd,
- };
- // We want a thin 1-pixel line for kBarTopColor.
- SkScalar scalar_height = SkIntToScalar(bar_height);
- SkScalar highlight_width = 1 / scalar_height;
- SkScalar border_width = kBorderWidth / scalar_height;
- const SkScalar bar_points[] = {
- 0,
- border_width,
- border_width + highlight_width,
- SK_Scalar1 - border_width,
- SK_Scalar1,
- };
-
- const SkColor disabled_bar_colors[] = {
- kDisabledBarColorStart,
- kDisabledBarColorStart,
- kDisabledBarColorEnd,
- kDisabledBarColorEnd,
- };
-
- const SkScalar disabled_bar_points[] = {
- 0,
- border_width,
- SK_Scalar1 - border_width,
- SK_Scalar1
- };
-
- // Do not start from (kBorderWidth, kBorderWidth) because it makes gaps
- // between the inner and the border.
- FillRoundRect(canvas,
- bar_left, bar_top,
- progress_width, bar_height,
- kCornerRadius,
- enabled() ? bar_colors : disabled_bar_colors,
- enabled() ? bar_points : disabled_bar_points,
- enabled() ? arraysize(bar_colors) :
- arraysize(disabled_bar_colors),
- false);
-
- if (enabled()) {
- // Draw the highlight to the right.
- const SkColor highlight_colors[] = {
- SkColorSetA(kBarHighlightEnd, 0),
- kBarHighlightEnd,
- kBarHighlightEnd,
- };
- const SkScalar highlight_points[] = {
- 0, SK_Scalar1 - kBorderWidth / scalar_height, SK_Scalar1,
- };
- SkPaint paint;
- paint.setStyle(SkPaint::kFill_Style);
- paint.setFlags(SkPaint::kAntiAlias_Flag);
-
- SkPoint p[2];
- int highlight_left =
- std::max(0, progress_width - kHighlightWidth - kBorderWidth);
- p[0].iset(highlight_left, 0);
- p[1].iset(progress_width, 0);
- paint.setShader(SkGradientShader::MakeLinear(
- p, highlight_colors, highlight_points, arraysize(highlight_colors),
- SkShader::kClamp_TileMode));
- paint.setXfermodeMode(SkXfermode::kSrcOver_Mode);
- canvas->DrawRect(gfx::Rect(highlight_left, 0,
- kHighlightWidth + kBorderWidth, bar_height),
- paint);
- }
-
- canvas->Restore();
- }
-
- // Draw bar stroke
- StrokeRoundRect(canvas,
- bar_left, bar_top, progress_width, bar_height,
- kCornerRadius,
- enabled() ? kBarBorderColor : kDisabledBarBorderColor,
- kBorderWidth);
+ SkPath background_path;
+ AddPossiblyRoundRectToPath(content_bounds, &background_path);
+ SkPaint background_paint;
+ background_paint.setStyle(SkPaint::kFill_Style);
+ background_paint.setFlags(SkPaint::kAntiAlias_Flag);
+ background_paint.setColor(GetBackgroundColor());
+ canvas->DrawPath(background_path, background_paint);
+
+ // Draw slice.
+ SkPath slice_path;
+ double time = indeterminate_bar_animation_->GetCurrentValue();
+
+ // The animation spec corresponds to the material design lite's parameter.
+ // (cf. https://github.com/google/material-design-lite/)
+ double bar1_left;
+ double bar1_width;
+ double bar2_left;
+ double bar2_width;
+ if (time < 0.50) {
+ bar1_left = time / 2;
+ bar1_width = time * 1.5;
+ bar2_left = 0;
+ bar2_width = 0;
+ } else if (time < 0.75) {
+ bar1_left = time * 3 - 1.25;
+ bar1_width = 0.75 - (time - 0.5) * 3;
+ bar2_left = 0;
+ bar2_width = time - 0.5;
+ } else {
+ bar1_left = 1;
+ bar1_width = 0;
+ bar2_left = (time - 0.75) * 4;
+ bar2_width = 0.25 - (time - 0.75);
}
+
+ int bar1_x = static_cast<int>(content_bounds.width() * bar1_left);
+ int bar1_w =
+ std::min(static_cast<int>(content_bounds.width() * bar1_width + 0.5),
+ content_bounds.width() - bar1_x);
+ int bar2_x = static_cast<int>(content_bounds.width() * bar2_left);
+ int bar2_w =
+ std::min(static_cast<int>(content_bounds.width() * bar2_width + 0.5),
+ content_bounds.width() - bar2_x);
+
+ gfx::Rect slice_bounds = content_bounds;
+ slice_bounds.set_x(content_bounds.x() + bar1_x);
+ slice_bounds.set_width(bar1_w);
+ AddPossiblyRoundRectToPath(slice_bounds, &slice_path);
+ slice_bounds.set_x(content_bounds.x() + bar2_x);
+ slice_bounds.set_width(bar2_w);
+ AddPossiblyRoundRectToPath(slice_bounds, &slice_path);
+
+ SkPaint slice_paint;
+ slice_paint.setStyle(SkPaint::kFill_Style);
+ slice_paint.setFlags(SkPaint::kAntiAlias_Flag);
+ slice_paint.setColor(GetForegroundColor());
+ canvas->DrawPath(slice_path, slice_paint);
}
} // namespace views

Powered by Google App Engine
This is Rietveld 408576698