15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2011 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/views/controls/scrollbar/base_scroll_bar_thumb.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gfx/canvas.h"
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gfx/rect.h"
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/views/controls/scrollbar/base_scroll_bar.h"
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The distance the mouse can be dragged outside the bounds of the thumb during
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// dragging before the scrollbar will snap back to its regular position.
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const int kScrollThumbDragOutSnap = 100;
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace views {
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)BaseScrollBarThumb::BaseScrollBarThumb(BaseScrollBar* scroll_bar)
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : scroll_bar_(scroll_bar),
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      drag_start_position_(-1),
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      mouse_offset_(-1),
232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      state_(CustomButton::STATE_NORMAL) {
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)BaseScrollBarThumb::~BaseScrollBarThumb() {
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BaseScrollBarThumb::SetSize(int size) {
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Make sure the thumb is never sized smaller than its minimum possible
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // display size.
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gfx::Size prefsize = GetPreferredSize();
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  size = std::max(size, scroll_bar_->IsHorizontal() ? prefsize.width() :
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                      prefsize.height());
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gfx::Rect thumb_bounds = bounds();
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (scroll_bar_->IsHorizontal()) {
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    thumb_bounds.set_width(size);
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    thumb_bounds.set_height(size);
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SetBoundsRect(thumb_bounds);
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int BaseScrollBarThumb::GetSize() const {
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (scroll_bar_->IsHorizontal())
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return width();
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return height();
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BaseScrollBarThumb::SetPosition(int position) {
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gfx::Rect thumb_bounds = bounds();
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gfx::Rect track_bounds = scroll_bar_->GetTrackBounds();
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (scroll_bar_->IsHorizontal()) {
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    thumb_bounds.set_x(track_bounds.x() + position);
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    thumb_bounds.set_y(track_bounds.y() + position);
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SetBoundsRect(thumb_bounds);
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int BaseScrollBarThumb::GetPosition() const {
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gfx::Rect track_bounds = scroll_bar_->GetTrackBounds();
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (scroll_bar_->IsHorizontal())
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return x() - track_bounds.x();
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return y() - track_bounds.y();
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BaseScrollBarThumb::OnMouseEntered(const ui::MouseEvent& event) {
692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  SetState(CustomButton::STATE_HOVERED);
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BaseScrollBarThumb::OnMouseExited(const ui::MouseEvent& event) {
732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  SetState(CustomButton::STATE_NORMAL);
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool BaseScrollBarThumb::OnMousePressed(const ui::MouseEvent& event) {
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  mouse_offset_ = scroll_bar_->IsHorizontal() ? event.x() : event.y();
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  drag_start_position_ = GetPosition();
792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  SetState(CustomButton::STATE_PRESSED);
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool BaseScrollBarThumb::OnMouseDragged(const ui::MouseEvent& event) {
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If the user moves the mouse more than |kScrollThumbDragOutSnap| outside
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // the bounds of the thumb, the scrollbar will snap the scroll back to the
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // point it was at before the drag began.
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (scroll_bar_->IsHorizontal()) {
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if ((event.y() < y() - kScrollThumbDragOutSnap) ||
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        (event.y() > (y() + height() + kScrollThumbDragOutSnap))) {
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      scroll_bar_->ScrollToThumbPosition(drag_start_position_, false);
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return true;
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if ((event.x() < x() - kScrollThumbDragOutSnap) ||
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        (event.x() > (x() + width() + kScrollThumbDragOutSnap))) {
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      scroll_bar_->ScrollToThumbPosition(drag_start_position_, false);
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return true;
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (scroll_bar_->IsHorizontal()) {
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int thumb_x = event.x() - mouse_offset_;
1022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (base::i18n::IsRTL())
1032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      thumb_x *= -1;
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scroll_bar_->ScrollToThumbPosition(GetPosition() + thumb_x, false);
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int thumb_y = event.y() - mouse_offset_;
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scroll_bar_->ScrollToThumbPosition(GetPosition() + thumb_y, false);
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BaseScrollBarThumb::OnMouseReleased(const ui::MouseEvent& event) {
1132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  SetState(HitTestPoint(event.location()) ?
1142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)           CustomButton::STATE_HOVERED : CustomButton::STATE_NORMAL);
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BaseScrollBarThumb::OnMouseCaptureLost() {
1182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  SetState(CustomButton::STATE_HOVERED);
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)CustomButton::ButtonState BaseScrollBarThumb::GetState() const {
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return state_;
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BaseScrollBarThumb::SetState(CustomButton::ButtonState state) {
1262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (state_ == state)
1272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
1282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  CustomButton::ButtonState old_state = state_;
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  state_ = state;
1312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scroll_bar_->OnThumbStateChanged(old_state, state);
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SchedulePaint();
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace views
136