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