1// Copyright 2013 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/scrollbar/overlay_scroll_bar.h"
6
7#include "third_party/skia/include/core/SkColor.h"
8#include "third_party/skia/include/core/SkXfermode.h"
9#include "ui/gfx/canvas.h"
10#include "ui/views/background.h"
11#include "ui/views/border.h"
12#include "ui/views/controls/scrollbar/base_scroll_bar_thumb.h"
13
14namespace views {
15namespace {
16
17const int kScrollbarWidth = 10;
18const int kThumbInsetInside = 3;
19const int kThumbInsetFromEdge = 1;
20const int kThumbCornerRadius = 2;
21const int kThumbMinimumSize = kScrollbarWidth;
22const int kThumbHoverAlpha = 128;
23const int kThumbDefaultAlpha = 64;
24
25class OverlayScrollBarThumb : public BaseScrollBarThumb,
26                              public gfx::AnimationDelegate {
27 public:
28  explicit OverlayScrollBarThumb(BaseScrollBar* scroll_bar);
29  virtual ~OverlayScrollBarThumb();
30
31 protected:
32  // View overrides:
33  virtual gfx::Size GetPreferredSize() const OVERRIDE;
34  virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE;
35
36  // gfx::AnimationDelegate overrides:
37  virtual void AnimationProgressed(const gfx::Animation* animation) OVERRIDE;
38
39 private:
40  double animation_opacity_;
41  DISALLOW_COPY_AND_ASSIGN(OverlayScrollBarThumb);
42};
43
44OverlayScrollBarThumb::OverlayScrollBarThumb(BaseScrollBar* scroll_bar)
45    : BaseScrollBarThumb(scroll_bar),
46      animation_opacity_(0.0) {
47  // This is necessary, otherwise the thumb will be rendered below the views if
48  // those views paint to their own layers.
49  SetPaintToLayer(true);
50  SetFillsBoundsOpaquely(false);
51}
52
53OverlayScrollBarThumb::~OverlayScrollBarThumb() {
54}
55
56gfx::Size OverlayScrollBarThumb::GetPreferredSize() const {
57  return gfx::Size(kThumbMinimumSize, kThumbMinimumSize);
58}
59
60void OverlayScrollBarThumb::OnPaint(gfx::Canvas* canvas) {
61  gfx::Rect local_bounds(GetLocalBounds());
62  SkPaint paint;
63  int alpha = kThumbDefaultAlpha * animation_opacity_;
64  if (GetState() == CustomButton::STATE_HOVERED) {
65    alpha = kThumbHoverAlpha * animation_opacity_;
66  } else if(GetState() == CustomButton::STATE_PRESSED) {
67    // If we are in pressed state, no need to worry about animation,
68    // just display the deeper color.
69    alpha = kThumbHoverAlpha;
70  }
71
72  paint.setStyle(SkPaint::kFill_Style);
73  paint.setColor(SkColorSetARGB(alpha, 0, 0, 0));
74  canvas->DrawRoundRect(local_bounds, kThumbCornerRadius, paint);
75}
76
77void OverlayScrollBarThumb::AnimationProgressed(
78    const gfx::Animation* animation) {
79  animation_opacity_ = animation->GetCurrentValue();
80  SchedulePaint();
81}
82
83}  // namespace
84
85OverlayScrollBar::OverlayScrollBar(bool horizontal)
86    : BaseScrollBar(horizontal, new OverlayScrollBarThumb(this)),
87      animation_(static_cast<OverlayScrollBarThumb*>(GetThumb())) {
88  set_notify_enter_exit_on_child(true);
89}
90
91OverlayScrollBar::~OverlayScrollBar() {
92}
93
94gfx::Rect OverlayScrollBar::GetTrackBounds() const {
95  gfx::Rect local_bounds(GetLocalBounds());
96  if (IsHorizontal()) {
97    local_bounds.Inset(kThumbInsetFromEdge, kThumbInsetInside,
98                       kThumbInsetFromEdge, kThumbInsetFromEdge);
99  } else {
100    local_bounds.Inset(kThumbInsetInside, kThumbInsetFromEdge,
101                       kThumbInsetFromEdge, kThumbInsetFromEdge);
102  }
103  gfx::Size track_size = local_bounds.size();
104  track_size.SetToMax(GetThumb()->size());
105  local_bounds.set_size(track_size);
106  return local_bounds;
107}
108
109int OverlayScrollBar::GetLayoutSize() const {
110  return 0;
111}
112
113int OverlayScrollBar::GetContentOverlapSize() const {
114  return kScrollbarWidth;
115}
116
117void OverlayScrollBar::OnMouseEnteredScrollView(const ui::MouseEvent& event) {
118  animation_.Show();
119}
120
121void OverlayScrollBar::OnMouseExitedScrollView(const ui::MouseEvent& event) {
122  animation_.Hide();
123}
124
125void OverlayScrollBar::OnGestureEvent(ui::GestureEvent* event) {
126  switch (event->type()) {
127    case ui::ET_GESTURE_SCROLL_BEGIN:
128      animation_.Show();
129      break;
130    case ui::ET_GESTURE_SCROLL_END:
131    case ui::ET_SCROLL_FLING_START:
132    case ui::ET_GESTURE_END:
133      animation_.Hide();
134      break;
135    default:
136      break;
137  }
138  BaseScrollBar::OnGestureEvent(event);
139}
140
141gfx::Size OverlayScrollBar::GetPreferredSize() const {
142  return gfx::Size();
143}
144
145void OverlayScrollBar::Layout() {
146  gfx::Rect thumb_bounds = GetTrackBounds();
147  BaseScrollBarThumb* thumb = GetThumb();
148  if (IsHorizontal()) {
149    thumb_bounds.set_x(thumb->x());
150    thumb_bounds.set_width(thumb->width());
151  } else {
152    thumb_bounds.set_y(thumb->y());
153    thumb_bounds.set_height(thumb->height());
154  }
155  thumb->SetBoundsRect(thumb_bounds);
156}
157
158void OverlayScrollBar::OnPaint(gfx::Canvas* canvas) {
159}
160
161}  // namespace views
162