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

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: fix test failure 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 hovered, the thumb takes up the full width. Otherwise, it's a bit
21 const int kThumbCornerRadius = 2; 21 // slimmer.
22 const int kThumbMinimumSize = kScrollbarWidth; 22 const int kThumbUnhoveredDifference = 4;
23 const int kThumbHoverAlpha = 128; 23 const int kThumbStroke = 1;
24 const int kThumbDefaultAlpha = 64; 24 const float kThumbHoverAlpha = 0.5f;
25 25 const float kThumbDefaultAlpha = 0.3f;
26 class OverlayScrollBarThumb : public BaseScrollBarThumb,
27 public gfx::AnimationDelegate {
28 public:
29 explicit OverlayScrollBarThumb(BaseScrollBar* scroll_bar);
30 ~OverlayScrollBarThumb() override;
31
32 protected:
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),
47 animation_opacity_(0.0) {
48 // This is necessary, otherwise the thumb will be rendered below the views if
49 // those views paint to their own layers.
50 SetPaintToLayer(true);
51 layer()->SetFillsBoundsOpaquely(false);
52 }
53
54 OverlayScrollBarThumb::~OverlayScrollBarThumb() {
55 }
56
57 gfx::Size OverlayScrollBarThumb::GetPreferredSize() const {
58 return gfx::Size(kThumbMinimumSize, kThumbMinimumSize);
59 }
60
61 void OverlayScrollBarThumb::OnPaint(gfx::Canvas* canvas) {
62 gfx::Rect local_bounds(GetLocalBounds());
63 SkPaint paint;
64 int alpha = kThumbDefaultAlpha * animation_opacity_;
65 if (GetState() == CustomButton::STATE_HOVERED) {
66 alpha = kThumbHoverAlpha * animation_opacity_;
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 }
77
78 void OverlayScrollBarThumb::AnimationProgressed(
79 const gfx::Animation* animation) {
80 animation_opacity_ = animation->GetCurrentValue();
81 SchedulePaint();
82 }
83 26
84 } // namespace 27 } // namespace
85 28
29 OverlayScrollBar::Thumb::Thumb(OverlayScrollBar* scroll_bar)
30 : BaseScrollBarThumb(scroll_bar), scroll_bar_(scroll_bar) {
31 SetPaintToLayer(true);
32 // Animate all changes to the layer except the first one.
33 OnStateChanged();
34 layer()->SetAnimator(ui::LayerAnimator::CreateImplicitAnimator());
35 }
36
37 OverlayScrollBar::Thumb::~Thumb() {}
38
39 gfx::Size OverlayScrollBar::Thumb::GetPreferredSize() const {
40 return gfx::Size(kThumbThickness, kThumbThickness);
41 }
42
43 void OverlayScrollBar::Thumb::OnPaint(gfx::Canvas* canvas) {
44 SkPaint fill_paint;
45 fill_paint.setStyle(SkPaint::kFill_Style);
46 fill_paint.setColor(SK_ColorBLACK);
47 gfx::RectF fill_bounds(GetLocalBounds());
48 fill_bounds.Inset(gfx::InsetsF(kThumbStroke, kThumbStroke,
49 IsHorizontal() ? 0 : kThumbStroke,
50 IsHorizontal() ? kThumbStroke : 0));
51 canvas->DrawRect(fill_bounds, fill_paint);
52
53 SkPaint stroke_paint;
54 stroke_paint.setStyle(SkPaint::kStroke_Style);
55 stroke_paint.setColor(SK_ColorWHITE);
56 stroke_paint.setStrokeWidth(kThumbStroke);
57 gfx::RectF stroke_bounds(fill_bounds);
58 stroke_bounds.Inset(gfx::InsetsF(-0.5f));
59 // The stroke doesn't apply to the far edge of the thumb.
60 SkPath path;
61 path.moveTo(gfx::PointFToSkPoint(stroke_bounds.top_right()));
62 path.lineTo(gfx::PointFToSkPoint(stroke_bounds.origin()));
63 path.lineTo(gfx::PointFToSkPoint(stroke_bounds.bottom_left()));
64 if (IsHorizontal()) {
65 path.moveTo(gfx::PointFToSkPoint(stroke_bounds.bottom_right()));
66 path.close();
67 } else {
68 path.lineTo(gfx::PointFToSkPoint(stroke_bounds.bottom_right()));
69 }
70 canvas->DrawPath(path, stroke_paint);
71 }
72
73 void OverlayScrollBar::Thumb::OnBoundsChanged(
74 const gfx::Rect& previous_bounds) {
75 scroll_bar_->Show();
76 // Don't start the hide countdown if the thumb is still hovered or pressed.
77 if (GetState() == CustomButton::STATE_NORMAL)
78 scroll_bar_->StartHideCountdown();
79 }
80
81 void OverlayScrollBar::Thumb::OnStateChanged() {
82 if (GetState() == CustomButton::STATE_NORMAL) {
83 gfx::Transform translation;
84 translation.Translate(
85 gfx::Vector2d(IsHorizontal() ? 0 : kThumbUnhoveredDifference,
86 IsHorizontal() ? kThumbUnhoveredDifference : 0));
87 layer()->SetTransform(translation);
88 layer()->SetOpacity(kThumbDefaultAlpha);
89
90 if (GetWidget())
91 scroll_bar_->StartHideCountdown();
92 } else {
93 layer()->SetTransform(gfx::Transform());
94 layer()->SetOpacity(kThumbHoverAlpha);
95 }
96 }
97
86 OverlayScrollBar::OverlayScrollBar(bool horizontal) 98 OverlayScrollBar::OverlayScrollBar(bool horizontal)
87 : BaseScrollBar(horizontal, new OverlayScrollBarThumb(this)), 99 : BaseScrollBar(horizontal, new Thumb(this)), hide_timer_(false, false) {
88 animation_(static_cast<OverlayScrollBarThumb*>(GetThumb())) {
89 set_notify_enter_exit_on_child(true); 100 set_notify_enter_exit_on_child(true);
101 SetPaintToLayer(true);
102 layer()->SetMasksToBounds(true);
103 layer()->SetFillsBoundsOpaquely(false);
90 } 104 }
91 105
92 OverlayScrollBar::~OverlayScrollBar() { 106 OverlayScrollBar::~OverlayScrollBar() {
93 } 107 }
94 108
95 gfx::Rect OverlayScrollBar::GetTrackBounds() const { 109 gfx::Rect OverlayScrollBar::GetTrackBounds() const {
96 gfx::Rect local_bounds(GetLocalBounds()); 110 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 } 111 }
109 112
110 int OverlayScrollBar::GetLayoutSize() const { 113 int OverlayScrollBar::GetLayoutSize() const {
111 return 0; 114 return 0;
112 } 115 }
113 116
114 int OverlayScrollBar::GetContentOverlapSize() const { 117 int OverlayScrollBar::GetContentOverlapSize() const {
115 return kScrollbarWidth; 118 return kThumbThickness;
116 } 119 }
117 120
118 void OverlayScrollBar::OnMouseEnteredScrollView(const ui::MouseEvent& event) { 121 void OverlayScrollBar::OnMouseEntered(const ui::MouseEvent& event) {
119 animation_.Show(); 122 Show();
120 } 123 }
121 124
122 void OverlayScrollBar::OnMouseExitedScrollView(const ui::MouseEvent& event) { 125 void OverlayScrollBar::OnMouseExited(const ui::MouseEvent& event) {
123 animation_.Hide(); 126 StartHideCountdown();
124 } 127 }
125 128
126 void OverlayScrollBar::OnGestureEvent(ui::GestureEvent* event) { 129 void OverlayScrollBar::Show() {
127 switch (event->type()) { 130 layer()->SetOpacity(1.0f);
128 case ui::ET_GESTURE_SCROLL_BEGIN: 131 hide_timer_.Stop();
129 animation_.Show(); 132 }
130 break; 133
131 case ui::ET_GESTURE_SCROLL_END: 134 void OverlayScrollBar::Hide() {
132 case ui::ET_SCROLL_FLING_START: 135 ui::ScopedLayerAnimationSettings settings(layer()->GetAnimator());
133 case ui::ET_GESTURE_END: 136 settings.SetTransitionDuration(base::TimeDelta::FromMilliseconds(200));
134 animation_.Hide(); 137 layer()->SetOpacity(0.0f);
135 break; 138 }
136 default: 139
137 break; 140 void OverlayScrollBar::StartHideCountdown() {
138 } 141 if (IsMouseHovered())
139 BaseScrollBar::OnGestureEvent(event); 142 return;
143 hide_timer_.Start(
144 FROM_HERE, base::TimeDelta::FromSeconds(1),
145 base::Bind(&OverlayScrollBar::Hide, base::Unretained(this)));
140 } 146 }
141 147
142 void OverlayScrollBar::Layout() { 148 void OverlayScrollBar::Layout() {
143 gfx::Rect thumb_bounds = GetTrackBounds(); 149 gfx::Rect thumb_bounds = GetTrackBounds();
144 BaseScrollBarThumb* thumb = GetThumb(); 150 BaseScrollBarThumb* thumb = GetThumb();
145 if (IsHorizontal()) { 151 if (IsHorizontal()) {
146 thumb_bounds.set_x(thumb->x()); 152 thumb_bounds.set_x(thumb->x());
147 thumb_bounds.set_width(thumb->width()); 153 thumb_bounds.set_width(thumb->width());
148 } else { 154 } else {
149 thumb_bounds.set_y(thumb->y()); 155 thumb_bounds.set_y(thumb->y());
150 thumb_bounds.set_height(thumb->height()); 156 thumb_bounds.set_height(thumb->height());
151 } 157 }
152 thumb->SetBoundsRect(thumb_bounds); 158 thumb->SetBoundsRect(thumb_bounds);
153 } 159 }
154 160
155 } // namespace views 161 } // namespace views
OLDNEW
« no previous file with comments | « ui/views/controls/scrollbar/overlay_scroll_bar.h ('k') | ui/views/controls/scrollbar/scroll_bar.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698