1 // Copyright (c) 2011 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/base_scroll_bar_thumb.h"
6
7 #include "ui/gfx/canvas.h"
8 #include "ui/gfx/geometry/rect.h"
9 #include "ui/views/controls/scrollbar/scroll_bar.h"
10 #include "ui/views/metadata/metadata_impl_macros.h"
11
12 namespace {
13 // The distance the mouse can be dragged outside the bounds of the thumb during
14 // dragging before the scrollbar will snap back to its regular position.
15 static constexpr int kScrollThumbDragOutSnap = 100;
16 } // namespace
17
18 namespace views {
19
BaseScrollBarThumb(ScrollBar * scroll_bar)20 BaseScrollBarThumb::BaseScrollBarThumb(ScrollBar* scroll_bar)
21 : scroll_bar_(scroll_bar),
22 drag_start_position_(-1),
23 mouse_offset_(-1),
24 state_(Button::STATE_NORMAL) {}
25
26 BaseScrollBarThumb::~BaseScrollBarThumb() = default;
27
SetLength(int length)28 void BaseScrollBarThumb::SetLength(int length) {
29 // Make sure the thumb is never sized smaller than its minimum possible
30 // display size.
31 gfx::Size size = GetPreferredSize();
32 size.SetToMax(
33 gfx::Size(IsHorizontal() ? length : 0, IsHorizontal() ? 0 : length));
34 SetSize(size);
35 }
36
GetSize() const37 int BaseScrollBarThumb::GetSize() const {
38 if (IsHorizontal())
39 return width();
40 return height();
41 }
42
SetPosition(int position)43 void BaseScrollBarThumb::SetPosition(int position) {
44 gfx::Rect thumb_bounds = bounds();
45 gfx::Rect track_bounds = scroll_bar_->GetTrackBounds();
46 if (IsHorizontal()) {
47 thumb_bounds.set_x(track_bounds.x() + position);
48 } else {
49 thumb_bounds.set_y(track_bounds.y() + position);
50 }
51 SetBoundsRect(thumb_bounds);
52 }
53
GetPosition() const54 int BaseScrollBarThumb::GetPosition() const {
55 gfx::Rect track_bounds = scroll_bar_->GetTrackBounds();
56 if (IsHorizontal())
57 return x() - track_bounds.x();
58 return y() - track_bounds.y();
59 }
60
OnMouseEntered(const ui::MouseEvent & event)61 void BaseScrollBarThumb::OnMouseEntered(const ui::MouseEvent& event) {
62 SetState(Button::STATE_HOVERED);
63 }
64
OnMouseExited(const ui::MouseEvent & event)65 void BaseScrollBarThumb::OnMouseExited(const ui::MouseEvent& event) {
66 SetState(Button::STATE_NORMAL);
67 }
68
OnMousePressed(const ui::MouseEvent & event)69 bool BaseScrollBarThumb::OnMousePressed(const ui::MouseEvent& event) {
70 mouse_offset_ = IsHorizontal() ? event.x() : event.y();
71 drag_start_position_ = GetPosition();
72 SetState(Button::STATE_PRESSED);
73 return true;
74 }
75
OnMouseDragged(const ui::MouseEvent & event)76 bool BaseScrollBarThumb::OnMouseDragged(const ui::MouseEvent& event) {
77 // If the user moves the mouse more than |kScrollThumbDragOutSnap| outside
78 // the bounds of the thumb, the scrollbar will snap the scroll back to the
79 // point it was at before the drag began.
80 if (IsHorizontal()) {
81 if ((event.y() < y() - kScrollThumbDragOutSnap) ||
82 (event.y() > (y() + height() + kScrollThumbDragOutSnap))) {
83 scroll_bar_->ScrollToThumbPosition(drag_start_position_, false);
84 return true;
85 }
86 } else {
87 if ((event.x() < x() - kScrollThumbDragOutSnap) ||
88 (event.x() > (x() + width() + kScrollThumbDragOutSnap))) {
89 scroll_bar_->ScrollToThumbPosition(drag_start_position_, false);
90 return true;
91 }
92 }
93 if (IsHorizontal()) {
94 int thumb_x = event.x() - mouse_offset_;
95 if (base::i18n::IsRTL())
96 thumb_x *= -1;
97 scroll_bar_->ScrollToThumbPosition(GetPosition() + thumb_x, false);
98 } else {
99 int thumb_y = event.y() - mouse_offset_;
100 scroll_bar_->ScrollToThumbPosition(GetPosition() + thumb_y, false);
101 }
102 return true;
103 }
104
OnMouseReleased(const ui::MouseEvent & event)105 void BaseScrollBarThumb::OnMouseReleased(const ui::MouseEvent& event) {
106 SetState(HitTestPoint(event.location()) ? Button::STATE_HOVERED
107 : Button::STATE_NORMAL);
108 }
109
OnMouseCaptureLost()110 void BaseScrollBarThumb::OnMouseCaptureLost() {
111 SetState(Button::STATE_HOVERED);
112 }
113
GetState() const114 Button::ButtonState BaseScrollBarThumb::GetState() const {
115 return state_;
116 }
117
SetState(Button::ButtonState state)118 void BaseScrollBarThumb::SetState(Button::ButtonState state) {
119 if (state_ == state)
120 return;
121
122 state_ = state;
123 OnStateChanged();
124 }
125
OnStateChanged()126 void BaseScrollBarThumb::OnStateChanged() {
127 SchedulePaint();
128 }
129
IsHorizontal() const130 bool BaseScrollBarThumb::IsHorizontal() const {
131 return scroll_bar_->IsHorizontal();
132 }
133
134 BEGIN_METADATA(BaseScrollBarThumb, View)
135 END_METADATA
136
137 } // namespace views
138