Chromium Code Reviews| 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..475233b3fe11673edffdf6f672e880175e439238 100644 |
| --- a/ui/views/controls/progress_bar.cc |
| +++ b/ui/views/controls/progress_bar.cc |
| @@ -14,178 +14,47 @@ |
| #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() : current_value_(0.0), preferred_height_(5) {} |
| 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::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(); |
| - } |
| -} |
| - |
| -void ProgressBar::SetValue(double value) { |
| - if (value != current_value_) { |
| - current_value_ = value; |
| - SchedulePaint(); |
| - } |
| -} |
| - |
| -void ProgressBar::SetTooltipText(const base::string16& tooltip_text) { |
| - tooltip_text_ = tooltip_text; |
| -} |
| - |
| -bool ProgressBar::GetTooltipText(const gfx::Point& p, |
| - base::string16* tooltip) const { |
| - DCHECK(tooltip); |
| - *tooltip = tooltip_text_; |
| - return !tooltip_text_.empty(); |
| -} |
| - |
| void ProgressBar::GetAccessibleState(ui::AXViewState* state) { |
| state->role = ui::AX_ROLE_PROGRESS_INDICATOR; |
| state->AddStateFlag(ui::AX_STATE_READ_ONLY); |
| } |
| gfx::Size ProgressBar::GetPreferredSize() const { |
| - gfx::Size pref_size(100, 11); |
| + // 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; |
| @@ -195,125 +64,143 @@ const char* ProgressBar::GetClassName() const { |
| return kViewClassName; |
| } |
| +SkColor ProgressBar::GetForegroundColor() const { |
|
sky
2016/09/13 02:30:08
definition/declaration order is off.
Evan Stade
2016/09/13 15:45:39
Done.
|
| + return GetNativeTheme()->GetSystemColor( |
| + ui::NativeTheme::kColorId_CallToActionColor); |
| +} |
| + |
| +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::OnPaint(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(); |
| + if (IsIndeterminate()) |
| + return OnPaintIndeterminate(canvas); |
| - const int progress_width = |
| - static_cast<int>(bar_width * GetNormalizedValue() + 0.5); |
| + gfx::Rect content_bounds = GetContentsBounds(); |
| // 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(); |
| + 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) { |
| + double adjusted_value = (value < 0.0 || value > 1.0) ? -1.0 : value; |
| + |
| + if (adjusted_value != current_value_) { |
|
sky
2016/09/13 02:30:08
optional: early return.
Evan Stade
2016/09/13 15:45:39
Done.
|
| + current_value_ = value; |
| + if (IsIndeterminate()) { |
| + indeterminate_bar_animation_.reset(new gfx::LinearAnimation(this)); |
| + indeterminate_bar_animation_->SetDuration(2000); // In milliseconds. |
| + indeterminate_bar_animation_->Start(); |
| + } else { |
| + SchedulePaint(); |
|
sky
2016/09/13 02:30:08
Does this need to reset indeterminate_bar_animatio
Evan Stade
2016/09/13 15:45:39
Done.
|
| } |
| + } |
| +} |
| + |
| +void ProgressBar::AnimationProgressed(const gfx::Animation* animation) { |
| + DCHECK_EQ(animation, indeterminate_bar_animation_.get()); |
| + DCHECK(IsIndeterminate()); |
| + SchedulePaint(); |
| +} |
| - // Draw bar stroke |
| - StrokeRoundRect(canvas, |
| - bar_left, bar_top, progress_width, bar_height, |
| - kCornerRadius, |
| - enabled() ? kBarBorderColor : kDisabledBarBorderColor, |
| - kBorderWidth); |
| +void ProgressBar::AnimationEnded(const gfx::Animation* animation) { |
| + DCHECK_EQ(animation, indeterminate_bar_animation_.get()); |
| + // Restarts animation. |
| + if (IsIndeterminate()) |
| + indeterminate_bar_animation_->Start(); |
| +} |
| + |
| +bool ProgressBar::IsIndeterminate() { |
| + return current_value_ < 0.0; |
| +} |
| + |
| +void ProgressBar::OnPaintIndeterminate(gfx::Canvas* 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; |
| + 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 |