| OLD | NEW |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 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 | 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/events/gesture_detection/snap_scroll_controller.h" | 5 #include "ui/events/gesture_detection/snap_scroll_controller.h" |
| 6 | 6 |
| 7 #include <cmath> | 7 #include <cmath> |
| 8 | 8 |
| 9 #include "ui/events/gesture_detection/motion_event.h" | 9 #include "ui/events/gesture_detection/motion_event.h" |
| 10 #include "ui/gfx/display.h" | |
| 11 | 10 |
| 12 namespace ui { | 11 namespace ui { |
| 13 namespace { | 12 namespace { |
| 14 const int kSnapBound = 16; | |
| 15 const float kMinSnapChannelDistance = kSnapBound; | |
| 16 const float kMaxSnapChannelDistance = kMinSnapChannelDistance * 3.f; | |
| 17 const float kSnapChannelDipsPerScreenDip = kMinSnapChannelDistance / 480.f; | |
| 18 | 13 |
| 19 float CalculateChannelDistance(const gfx::Display& display) { | 14 // Minimum ratio between initial X and Y motion to allow snapping. |
| 20 if (display.bounds().IsEmpty()) | 15 const float kMinSnapRatio = 1.25f; |
| 21 return kMinSnapChannelDistance; | 16 |
| 17 // Size of the snap rail relative to the initial snap bound threshold. |
| 18 const float kSnapBoundToChannelMultiplier = 1.5f; |
| 19 |
| 20 float CalculateChannelDistance(float snap_bound, |
| 21 const gfx::SizeF& display_size) { |
| 22 const float kMinChannelDistance = snap_bound * kSnapBoundToChannelMultiplier; |
| 23 const float kMaxChannelDistance = kMinChannelDistance * 3.f; |
| 24 const float kSnapChannelDipsPerScreenDip = kMinChannelDistance / 480.f; |
| 25 if (display_size.IsEmpty()) |
| 26 return kMinChannelDistance; |
| 22 | 27 |
| 23 float screen_size = | 28 float screen_size = |
| 24 std::abs(hypot(static_cast<float>(display.bounds().width()), | 29 std::abs(hypot(static_cast<float>(display_size.width()), |
| 25 static_cast<float>(display.bounds().height()))); | 30 static_cast<float>(display_size.height()))); |
| 26 | 31 |
| 27 float snap_channel_distance = screen_size * kSnapChannelDipsPerScreenDip; | 32 float snap_channel_distance = screen_size * kSnapChannelDipsPerScreenDip; |
| 28 return std::max(kMinSnapChannelDistance, | 33 return std::max(kMinChannelDistance, |
| 29 std::min(kMaxSnapChannelDistance, snap_channel_distance)); | 34 std::min(kMaxChannelDistance, snap_channel_distance)); |
| 30 } | 35 } |
| 31 | 36 |
| 32 } // namespace | 37 } // namespace |
| 33 | 38 |
| 34 | 39 SnapScrollController::SnapScrollController(float snap_bound, |
| 35 SnapScrollController::SnapScrollController(const gfx::Display& display) | 40 const gfx::SizeF& display_size) |
| 36 : channel_distance_(CalculateChannelDistance(display)), | 41 : snap_bound_(snap_bound), |
| 37 snap_scroll_mode_(SNAP_NONE), | 42 channel_distance_(CalculateChannelDistance(snap_bound, display_size)), |
| 38 first_touch_x_(-1), | 43 mode_(SNAP_NONE) { |
| 39 first_touch_y_(-1), | |
| 40 distance_x_(0), | |
| 41 distance_y_(0) {} | |
| 42 | |
| 43 SnapScrollController::~SnapScrollController() {} | |
| 44 | |
| 45 void SnapScrollController::UpdateSnapScrollMode(float distance_x, | |
| 46 float distance_y) { | |
| 47 if (snap_scroll_mode_ == SNAP_HORIZ || snap_scroll_mode_ == SNAP_VERT) { | |
| 48 distance_x_ += std::abs(distance_x); | |
| 49 distance_y_ += std::abs(distance_y); | |
| 50 if (snap_scroll_mode_ == SNAP_HORIZ) { | |
| 51 if (distance_y_ > channel_distance_) { | |
| 52 snap_scroll_mode_ = SNAP_NONE; | |
| 53 } else if (distance_x_ > channel_distance_) { | |
| 54 distance_x_ = 0; | |
| 55 distance_y_ = 0; | |
| 56 } | |
| 57 } else { | |
| 58 if (distance_x_ > channel_distance_) { | |
| 59 snap_scroll_mode_ = SNAP_NONE; | |
| 60 } else if (distance_y_ > channel_distance_) { | |
| 61 distance_x_ = 0; | |
| 62 distance_y_ = 0; | |
| 63 } | |
| 64 } | |
| 65 } | |
| 66 } | 44 } |
| 67 | 45 |
| 68 void SnapScrollController::SetSnapScrollingMode( | 46 SnapScrollController::~SnapScrollController() { |
| 47 } |
| 48 |
| 49 void SnapScrollController::SetSnapScrollMode( |
| 69 const MotionEvent& event, | 50 const MotionEvent& event, |
| 70 bool is_scale_gesture_detection_in_progress) { | 51 bool is_scale_gesture_detection_in_progress) { |
| 71 switch (event.GetAction()) { | 52 switch (event.GetAction()) { |
| 72 case MotionEvent::ACTION_DOWN: | 53 case MotionEvent::ACTION_DOWN: |
| 73 snap_scroll_mode_ = SNAP_NONE; | 54 mode_ = SNAP_PENDING; |
| 74 first_touch_x_ = event.GetX(); | 55 down_position_.set_x(event.GetX()); |
| 75 first_touch_y_ = event.GetY(); | 56 down_position_.set_y(event.GetY()); |
| 76 break; | 57 break; |
| 77 // Set scrolling mode to SNAP_X if scroll towards x-axis exceeds kSnapBound | 58 case MotionEvent::ACTION_MOVE: { |
| 78 // and movement towards y-axis is trivial. | 59 if (is_scale_gesture_detection_in_progress) |
| 79 // Set scrolling mode to SNAP_Y if scroll towards y-axis exceeds kSnapBound | 60 break; |
| 80 // and movement towards x-axis is trivial. | 61 |
| 81 // Scrolling mode will remain in SNAP_NONE for other conditions. | 62 if (mode_ != SNAP_PENDING) |
| 82 case MotionEvent::ACTION_MOVE: | 63 break; |
| 83 if (!is_scale_gesture_detection_in_progress && | 64 |
| 84 snap_scroll_mode_ == SNAP_NONE) { | 65 // Set scrolling mode to SNAP_X if scroll exceeds |snap_bound_| and the |
| 85 int x_diff = static_cast<int>(std::abs(event.GetX() - first_touch_x_)); | 66 // ratio of x movement to y movement is sufficiently large. Similarly for |
| 86 int y_diff = static_cast<int>(std::abs(event.GetY() - first_touch_y_)); | 67 // SNAP_Y and y movement. |
| 87 if (x_diff > kSnapBound && y_diff < kSnapBound) { | 68 float dx = std::abs(event.GetX() - down_position_.x()); |
| 88 snap_scroll_mode_ = SNAP_HORIZ; | 69 float dy = std::abs(event.GetY() - down_position_.y()); |
| 89 } else if (x_diff < kSnapBound && y_diff > kSnapBound) { | 70 float kMinSnapBound = snap_bound_; |
| 90 snap_scroll_mode_ = SNAP_VERT; | 71 float kMaxSnapBound = snap_bound_ * 2.f; |
| 91 } | 72 if (dx * dx + dy * dy > kMinSnapBound * kMinSnapBound) { |
| 73 if (!dy || (dx / dy > kMinSnapRatio && dy < kMaxSnapBound)) |
| 74 mode_ = SNAP_HORIZ; |
| 75 else if (!dx || (dy / dx > kMinSnapRatio && dx < kMaxSnapBound)) |
| 76 mode_ = SNAP_VERT; |
| 92 } | 77 } |
| 93 break; | 78 |
| 79 if (mode_ == SNAP_PENDING && dx > kMaxSnapBound && dy > kMaxSnapBound) |
| 80 mode_ = SNAP_NONE; |
| 81 } break; |
| 94 case MotionEvent::ACTION_UP: | 82 case MotionEvent::ACTION_UP: |
| 95 case MotionEvent::ACTION_CANCEL: | 83 case MotionEvent::ACTION_CANCEL: |
| 96 first_touch_x_ = -1; | 84 down_position_ = gfx::PointF(); |
| 97 first_touch_y_ = -1; | 85 accumulated_distance_ = gfx::Vector2dF(); |
| 98 distance_x_ = 0; | |
| 99 distance_y_ = 0; | |
| 100 break; | 86 break; |
| 101 default: | 87 default: |
| 102 break; | 88 break; |
| 103 } | 89 } |
| 104 } | 90 } |
| 105 | 91 |
| 92 void SnapScrollController::UpdateSnapScrollMode(float distance_x, |
| 93 float distance_y) { |
| 94 if (!IsSnappingScrolls()) |
| 95 return; |
| 96 |
| 97 accumulated_distance_ += |
| 98 gfx::Vector2dF(std::abs(distance_x), std::abs(distance_y)); |
| 99 if (mode_ == SNAP_HORIZ) { |
| 100 if (accumulated_distance_.y() > channel_distance_) |
| 101 mode_ = SNAP_NONE; |
| 102 else if (accumulated_distance_.x() > channel_distance_) |
| 103 accumulated_distance_ = gfx::Vector2dF(); |
| 104 } else if (mode_ == SNAP_VERT) { |
| 105 if (accumulated_distance_.x() > channel_distance_) |
| 106 mode_ = SNAP_NONE; |
| 107 else if (accumulated_distance_.y() > channel_distance_) |
| 108 accumulated_distance_ = gfx::Vector2dF(); |
| 109 } |
| 110 } |
| 111 |
| 112 bool SnapScrollController::IsSnapVertical() const { |
| 113 return mode_ == SNAP_VERT; |
| 114 } |
| 115 |
| 116 bool SnapScrollController::IsSnapHorizontal() const { |
| 117 return mode_ == SNAP_HORIZ; |
| 118 } |
| 119 |
| 120 bool SnapScrollController::IsSnappingScrolls() const { |
| 121 return IsSnapHorizontal() || IsSnapVertical(); |
| 122 } |
| 123 |
| 106 } // namespace ui | 124 } // namespace ui |
| OLD | NEW |