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

Side by Side Diff: ui/views/controls/scrollbar/overlay_scroll_bar.cc

Issue 2496643002: Implement Sebastien's overlay scrollbars for native UI (Views). (Closed)
Patch Set: clarify comment Created 4 years, 1 month 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 unified diff | Download patch
OLDNEW
1 // Copyright 2013 The Chromium Authors. All rights reserved. 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 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/scrollbar/overlay_scroll_bar.h" 5 #include "ui/views/controls/scrollbar/overlay_scroll_bar.h"
6 6
7 #include "base/macros.h" 7 #include "base/macros.h"
8 #include "third_party/skia/include/core/SkColor.h" 8 #include "third_party/skia/include/core/SkColor.h"
9 #include "third_party/skia/include/core/SkXfermode.h" 9 #include "third_party/skia/include/core/SkXfermode.h"
10 #include "ui/compositor/scoped_layer_animation_settings.h"
10 #include "ui/gfx/canvas.h" 11 #include "ui/gfx/canvas.h"
11 #include "ui/views/background.h" 12 #include "ui/views/background.h"
12 #include "ui/views/border.h" 13 #include "ui/views/border.h"
13 #include "ui/views/controls/scrollbar/base_scroll_bar_thumb.h"
14 14
15 namespace views { 15 namespace views {
16 namespace { 16 namespace {
17 17
18 const int kScrollbarWidth = 10; 18 // Total thickness of the thumb (matches visuals when hovered).
19 const int kThumbInsetInside = 3; 19 const int kThumbThickness = 11;
20 const int kThumbInsetFromEdge = 1; 20 // When unhovered, the thumb is slimmer by this amount of dip.
21 const int kThumbCornerRadius = 2; 21 const int kThumbUnhoveredDifference = 4;
22 const int kThumbMinimumSize = kScrollbarWidth; 22 const int kThumbStroke = 1;
23 const int kThumbHoverAlpha = 128; 23 const SkAlpha kThumbHoverAlpha = 0x80; // 0.5
24 const int kThumbDefaultAlpha = 64; 24 const SkAlpha kThumbDefaultAlpha = 0x4D; // 0.3
25 25
26 class OverlayScrollBarThumb : public BaseScrollBarThumb, 26 } // namespace
27 public gfx::AnimationDelegate {
28 public:
29 explicit OverlayScrollBarThumb(BaseScrollBar* scroll_bar);
30 ~OverlayScrollBarThumb() override;
31 27
32 protected: 28 OverlayScrollBar::Thumb::Thumb(OverlayScrollBar* scroll_bar)
33 // View overrides:
34 gfx::Size GetPreferredSize() const override;
35 void OnPaint(gfx::Canvas* canvas) override;
36
37 // gfx::AnimationDelegate overrides:
38 void AnimationProgressed(const gfx::Animation* animation) override;
39
40 private:
41 double animation_opacity_;
42 DISALLOW_COPY_AND_ASSIGN(OverlayScrollBarThumb);
43 };
44
45 OverlayScrollBarThumb::OverlayScrollBarThumb(BaseScrollBar* scroll_bar)
46 : BaseScrollBarThumb(scroll_bar), 29 : BaseScrollBarThumb(scroll_bar),
47 animation_opacity_(0.0) { 30 scroll_bar_(scroll_bar),
31 hover_animation_(this) {
48 // This is necessary, otherwise the thumb will be rendered below the views if 32 // This is necessary, otherwise the thumb will be rendered below the views if
49 // those views paint to their own layers. 33 // those views paint to their own layers.
50 SetPaintToLayer(true); 34 SetPaintToLayer(true);
51 layer()->SetFillsBoundsOpaquely(false); 35 layer()->SetFillsBoundsOpaquely(false);
36 layer()->SetOpacity(0);
52 } 37 }
53 38
54 OverlayScrollBarThumb::~OverlayScrollBarThumb() { 39 OverlayScrollBar::Thumb::~Thumb() {}
40
41 gfx::Size OverlayScrollBar::Thumb::GetPreferredSize() const {
42 return gfx::Size(kThumbThickness, kThumbThickness);
55 } 43 }
56 44
57 gfx::Size OverlayScrollBarThumb::GetPreferredSize() const { 45 void OverlayScrollBar::Thumb::OnPaint(gfx::Canvas* canvas) {
58 return gfx::Size(kThumbMinimumSize, kThumbMinimumSize); 46 SkAlpha alpha = kThumbHoverAlpha;
47 // If we are in pressed state, no need to worry about animation,
48 // just display the deeper color.
49 if (GetState() != CustomButton::STATE_PRESSED) {
50 alpha = hover_animation_.CurrentValueBetween(kThumbDefaultAlpha,
51 kThumbHoverAlpha);
52 }
53
54 SkPaint fill_paint;
55 fill_paint.setAntiAlias(true);
56 fill_paint.setStyle(SkPaint::kFill_Style);
57 fill_paint.setColor(SkColorSetA(SK_ColorBLACK, alpha));
58 gfx::RectF fill_bounds(GetLocalBounds());
59 const double slimmer_by =
60 hover_animation_.CurrentValueBetween(kThumbUnhoveredDifference, 0);
61 fill_bounds.Inset(gfx::InsetsF(IsHorizontal() ? slimmer_by : 0,
62 IsHorizontal() ? 0 : slimmer_by, 0, 0));
63 fill_bounds.Inset(gfx::InsetsF(kThumbStroke, kThumbStroke,
64 IsHorizontal() ? 0 : kThumbStroke,
65 IsHorizontal() ? kThumbStroke : 0));
66 canvas->DrawRect(fill_bounds, fill_paint);
67
68 SkPaint stroke_paint;
69 stroke_paint.setAntiAlias(true);
70 stroke_paint.setStyle(SkPaint::kFill_Style);
71 stroke_paint.setColor(SkColorSetA(SK_ColorWHITE, alpha));
72 stroke_paint.setStrokeWidth(kThumbStroke);
73 gfx::RectF stroke_bounds(fill_bounds);
74 stroke_bounds.Inset(gfx::InsetsF(-0.5f));
75 // The stroke doesn't apply to the far edge of the thumb.
76 SkPath path;
77 path.moveTo(gfx::PointFToSkPoint(stroke_bounds.top_right()));
78 path.lineTo(gfx::PointFToSkPoint(stroke_bounds.origin()));
79 path.lineTo(gfx::PointFToSkPoint(stroke_bounds.bottom_left()));
80 if (IsHorizontal()) {
81 path.moveTo(gfx::PointFToSkPoint(stroke_bounds.bottom_right()));
82 path.close();
83 } else {
84 path.lineTo(gfx::PointFToSkPoint(stroke_bounds.bottom_right()));
85 }
86 canvas->DrawPath(path, stroke_paint);
59 } 87 }
60 88
61 void OverlayScrollBarThumb::OnPaint(gfx::Canvas* canvas) { 89 void OverlayScrollBar::Thumb::OnBoundsChanged(
62 gfx::Rect local_bounds(GetLocalBounds()); 90 const gfx::Rect& previous_bounds) {
63 SkPaint paint; 91 scroll_bar_->ShowThumb();
64 int alpha = kThumbDefaultAlpha * animation_opacity_; 92 // Don't start the hide countdown if the thumb is still hovered or pressed.
65 if (GetState() == CustomButton::STATE_HOVERED) { 93 if (GetState() == CustomButton::STATE_NORMAL)
66 alpha = kThumbHoverAlpha * animation_opacity_; 94 scroll_bar_->StartThumbHideCountdown();
67 } else if(GetState() == CustomButton::STATE_PRESSED) {
68 // If we are in pressed state, no need to worry about animation,
69 // just display the deeper color.
70 alpha = kThumbHoverAlpha;
71 }
72
73 paint.setStyle(SkPaint::kFill_Style);
74 paint.setColor(SkColorSetARGB(alpha, 0, 0, 0));
75 canvas->DrawRoundRect(local_bounds, kThumbCornerRadius, paint);
76 } 95 }
77 96
78 void OverlayScrollBarThumb::AnimationProgressed( 97 void OverlayScrollBar::Thumb::SetState(CustomButton::ButtonState state) {
98 if (state != GetState()) {
99 if (state == CustomButton::STATE_NORMAL) {
100 hover_animation_.Hide();
101 scroll_bar_->StartThumbHideCountdown();
102 } else {
103 hover_animation_.Show();
sadrul 2016/11/12 03:01:10 Since the thumb has a layer, can you just animate
Evan Stade 2016/11/14 16:56:07 I've changed all animations to be applied to layer
104 }
105 }
106 BaseScrollBarThumb::SetState(state);
107 }
108
109 void OverlayScrollBar::Thumb::AnimationProgressed(
79 const gfx::Animation* animation) { 110 const gfx::Animation* animation) {
80 animation_opacity_ = animation->GetCurrentValue();
81 SchedulePaint(); 111 SchedulePaint();
82 } 112 }
83 113
84 } // namespace
85
86 OverlayScrollBar::OverlayScrollBar(bool horizontal) 114 OverlayScrollBar::OverlayScrollBar(bool horizontal)
87 : BaseScrollBar(horizontal, new OverlayScrollBarThumb(this)), 115 : BaseScrollBar(horizontal, new Thumb(this)),
88 animation_(static_cast<OverlayScrollBarThumb*>(GetThumb())) { 116 thumb_hide_timer_(false, false) {
89 set_notify_enter_exit_on_child(true); 117 set_notify_enter_exit_on_child(true);
90 } 118 }
91 119
92 OverlayScrollBar::~OverlayScrollBar() { 120 OverlayScrollBar::~OverlayScrollBar() {
93 } 121 }
94 122
95 gfx::Rect OverlayScrollBar::GetTrackBounds() const { 123 gfx::Rect OverlayScrollBar::GetTrackBounds() const {
96 gfx::Rect local_bounds(GetLocalBounds()); 124 return GetLocalBounds();
97 if (IsHorizontal()) {
98 local_bounds.Inset(kThumbInsetFromEdge, kThumbInsetInside,
99 kThumbInsetFromEdge, kThumbInsetFromEdge);
100 } else {
101 local_bounds.Inset(kThumbInsetInside, kThumbInsetFromEdge,
102 kThumbInsetFromEdge, kThumbInsetFromEdge);
103 }
104 gfx::Size track_size = local_bounds.size();
105 track_size.SetToMax(GetThumb()->size());
106 local_bounds.set_size(track_size);
107 return local_bounds;
108 } 125 }
109 126
110 int OverlayScrollBar::GetLayoutSize() const { 127 int OverlayScrollBar::GetLayoutSize() const {
111 return 0; 128 return 0;
112 } 129 }
113 130
114 int OverlayScrollBar::GetContentOverlapSize() const { 131 int OverlayScrollBar::GetContentOverlapSize() const {
115 return kScrollbarWidth; 132 return kThumbThickness;
116 } 133 }
117 134
118 void OverlayScrollBar::OnMouseEnteredScrollView(const ui::MouseEvent& event) { 135 void OverlayScrollBar::OnMouseEntered(const ui::MouseEvent& event) {
119 animation_.Show(); 136 ShowThumb();
120 } 137 }
121 138
122 void OverlayScrollBar::OnMouseExitedScrollView(const ui::MouseEvent& event) { 139 void OverlayScrollBar::OnMouseExited(const ui::MouseEvent& event) {
123 animation_.Hide(); 140 StartThumbHideCountdown();
124 } 141 }
125 142
126 void OverlayScrollBar::OnGestureEvent(ui::GestureEvent* event) { 143 void OverlayScrollBar::ShowThumb() {
127 switch (event->type()) { 144 GetThumb()->layer()->SetOpacity(1.0f);
128 case ui::ET_GESTURE_SCROLL_BEGIN: 145 thumb_hide_timer_.Stop();
129 animation_.Show(); 146 }
130 break; 147
131 case ui::ET_GESTURE_SCROLL_END: 148 void OverlayScrollBar::HideThumb() {
132 case ui::ET_SCROLL_FLING_START: 149 ui::ScopedLayerAnimationSettings settings(GetThumb()->layer()->GetAnimator());
133 case ui::ET_GESTURE_END: 150 settings.SetTransitionDuration(base::TimeDelta::FromMilliseconds(200));
134 animation_.Hide(); 151 GetThumb()->layer()->SetOpacity(0.0f);
135 break; 152 }
136 default: 153
137 break; 154 void OverlayScrollBar::StartThumbHideCountdown() {
138 } 155 if (IsMouseHovered())
139 BaseScrollBar::OnGestureEvent(event); 156 return;
157 thumb_hide_timer_.Start(
158 FROM_HERE, base::TimeDelta::FromSeconds(1),
159 base::Bind(&OverlayScrollBar::HideThumb, base::Unretained(this)));
140 } 160 }
141 161
142 void OverlayScrollBar::Layout() { 162 void OverlayScrollBar::Layout() {
143 gfx::Rect thumb_bounds = GetTrackBounds(); 163 gfx::Rect thumb_bounds = GetTrackBounds();
144 BaseScrollBarThumb* thumb = GetThumb(); 164 BaseScrollBarThumb* thumb = GetThumb();
145 if (IsHorizontal()) { 165 if (IsHorizontal()) {
146 thumb_bounds.set_x(thumb->x()); 166 thumb_bounds.set_x(thumb->x());
147 thumb_bounds.set_width(thumb->width()); 167 thumb_bounds.set_width(thumb->width());
148 } else { 168 } else {
149 thumb_bounds.set_y(thumb->y()); 169 thumb_bounds.set_y(thumb->y());
150 thumb_bounds.set_height(thumb->height()); 170 thumb_bounds.set_height(thumb->height());
151 } 171 }
152 thumb->SetBoundsRect(thumb_bounds); 172 thumb->SetBoundsRect(thumb_bounds);
153 } 173 }
154 174
155 } // namespace views 175 } // namespace views
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698