snap_scroll_controller.cc 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125
  1. // Copyright 2014 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. #include "ui/events/gesture_detection/snap_scroll_controller.h"
  5. #include <algorithm>
  6. #include <cmath>
  7. #include "ui/events/gesture_detection/motion_event.h"
  8. namespace ui {
  9. namespace {
  10. // Minimum ratio between initial X and Y motion to allow snapping.
  11. const float kMinSnapRatio = 1.25f;
  12. // Size of the snap rail relative to the initial snap bound threshold.
  13. const float kSnapBoundToChannelMultiplier = 1.5f;
  14. float CalculateChannelDistance(float snap_bound,
  15. const gfx::SizeF& display_size) {
  16. const float kMinChannelDistance = snap_bound * kSnapBoundToChannelMultiplier;
  17. const float kMaxChannelDistance = kMinChannelDistance * 3.f;
  18. const float kSnapChannelDipsPerScreenDip = kMinChannelDistance / 480.f;
  19. if (display_size.IsEmpty())
  20. return kMinChannelDistance;
  21. float screen_size =
  22. std::abs(hypot(static_cast<float>(display_size.width()),
  23. static_cast<float>(display_size.height())));
  24. float snap_channel_distance = screen_size * kSnapChannelDipsPerScreenDip;
  25. return std::max(kMinChannelDistance,
  26. std::min(kMaxChannelDistance, snap_channel_distance));
  27. }
  28. } // namespace
  29. SnapScrollController::SnapScrollController(float snap_bound,
  30. const gfx::SizeF& display_size)
  31. : snap_bound_(snap_bound),
  32. channel_distance_(CalculateChannelDistance(snap_bound, display_size)),
  33. mode_(SNAP_NONE) {
  34. }
  35. SnapScrollController::~SnapScrollController() {
  36. }
  37. void SnapScrollController::SetSnapScrollMode(
  38. const MotionEvent& event,
  39. bool is_scale_gesture_detection_in_progress) {
  40. switch (event.GetAction()) {
  41. case MotionEvent::Action::DOWN:
  42. mode_ = SNAP_PENDING;
  43. down_position_.set_x(event.GetX());
  44. down_position_.set_y(event.GetY());
  45. break;
  46. case MotionEvent::Action::MOVE: {
  47. if (is_scale_gesture_detection_in_progress)
  48. break;
  49. if (mode_ != SNAP_PENDING)
  50. break;
  51. // Set scrolling mode to SNAP_X if scroll exceeds |snap_bound_| and the
  52. // ratio of x movement to y movement is sufficiently large. Similarly for
  53. // SNAP_Y and y movement.
  54. float dx = std::abs(event.GetX() - down_position_.x());
  55. float dy = std::abs(event.GetY() - down_position_.y());
  56. float kMinSnapBound = snap_bound_;
  57. float kMaxSnapBound = snap_bound_ * 2.f;
  58. if (dx * dx + dy * dy > kMinSnapBound * kMinSnapBound) {
  59. if (!dy || (dx / dy > kMinSnapRatio && dy < kMaxSnapBound))
  60. mode_ = SNAP_HORIZ;
  61. else if (!dx || (dy / dx > kMinSnapRatio && dx < kMaxSnapBound))
  62. mode_ = SNAP_VERT;
  63. }
  64. if (mode_ == SNAP_PENDING && dx > kMaxSnapBound && dy > kMaxSnapBound)
  65. mode_ = SNAP_NONE;
  66. } break;
  67. case MotionEvent::Action::UP:
  68. case MotionEvent::Action::CANCEL:
  69. down_position_ = gfx::PointF();
  70. accumulated_distance_ = gfx::Vector2dF();
  71. break;
  72. default:
  73. break;
  74. }
  75. }
  76. void SnapScrollController::UpdateSnapScrollMode(float distance_x,
  77. float distance_y) {
  78. if (!IsSnappingScrolls())
  79. return;
  80. accumulated_distance_ +=
  81. gfx::Vector2dF(std::abs(distance_x), std::abs(distance_y));
  82. if (mode_ == SNAP_HORIZ) {
  83. if (accumulated_distance_.y() > channel_distance_)
  84. mode_ = SNAP_NONE;
  85. else if (accumulated_distance_.x() > channel_distance_)
  86. accumulated_distance_ = gfx::Vector2dF();
  87. } else if (mode_ == SNAP_VERT) {
  88. if (accumulated_distance_.x() > channel_distance_)
  89. mode_ = SNAP_NONE;
  90. else if (accumulated_distance_.y() > channel_distance_)
  91. accumulated_distance_ = gfx::Vector2dF();
  92. }
  93. }
  94. bool SnapScrollController::IsSnapVertical() const {
  95. return mode_ == SNAP_VERT;
  96. }
  97. bool SnapScrollController::IsSnapHorizontal() const {
  98. return mode_ == SNAP_HORIZ;
  99. }
  100. bool SnapScrollController::IsSnappingScrolls() const {
  101. return IsSnapHorizontal() || IsSnapVertical();
  102. }
  103. } // namespace ui