Index: ui/events/gesture_detection/snap_scroll_controller.cc |
diff --git a/ui/events/gesture_detection/snap_scroll_controller.cc b/ui/events/gesture_detection/snap_scroll_controller.cc |
index bde5a35602d6579cef87173f6fe7ed44c6755cf6..9ecf6b108c8a71030bc282bda1dbc1c5f065696a 100644 |
--- a/ui/events/gesture_detection/snap_scroll_controller.cc |
+++ b/ui/events/gesture_detection/snap_scroll_controller.cc |
@@ -7,100 +7,118 @@ |
#include <cmath> |
#include "ui/events/gesture_detection/motion_event.h" |
-#include "ui/gfx/display.h" |
namespace ui { |
namespace { |
-const int kSnapBound = 16; |
-const float kMinSnapChannelDistance = kSnapBound; |
-const float kMaxSnapChannelDistance = kMinSnapChannelDistance * 3.f; |
-const float kSnapChannelDipsPerScreenDip = kMinSnapChannelDistance / 480.f; |
-float CalculateChannelDistance(const gfx::Display& display) { |
- if (display.bounds().IsEmpty()) |
- return kMinSnapChannelDistance; |
+// Minimum ratio between initial X and Y motion to allow snapping. |
+const float kMinSnapRatio = 1.25f; |
+ |
+// Size of the snap rail relative to the initial snap bound threshold. |
+const float kSnapBoundToChannelMultiplier = 1.5f; |
+ |
+float CalculateChannelDistance(float snap_bound, |
+ const gfx::SizeF& display_size) { |
+ const float kMinChannelDistance = snap_bound * kSnapBoundToChannelMultiplier; |
+ const float kMaxChannelDistance = kMinChannelDistance * 3.f; |
+ const float kSnapChannelDipsPerScreenDip = kMinChannelDistance / 480.f; |
+ if (display_size.IsEmpty()) |
+ return kMinChannelDistance; |
float screen_size = |
- std::abs(hypot(static_cast<float>(display.bounds().width()), |
- static_cast<float>(display.bounds().height()))); |
+ std::abs(hypot(static_cast<float>(display_size.width()), |
+ static_cast<float>(display_size.height()))); |
float snap_channel_distance = screen_size * kSnapChannelDipsPerScreenDip; |
- return std::max(kMinSnapChannelDistance, |
- std::min(kMaxSnapChannelDistance, snap_channel_distance)); |
+ return std::max(kMinChannelDistance, |
+ std::min(kMaxChannelDistance, snap_channel_distance)); |
} |
} // namespace |
+SnapScrollController::SnapScrollController(float snap_bound, |
+ const gfx::SizeF& display_size) |
+ : snap_bound_(snap_bound), |
+ channel_distance_(CalculateChannelDistance(snap_bound, display_size)), |
+ mode_(SNAP_NONE) { |
+} |
-SnapScrollController::SnapScrollController(const gfx::Display& display) |
- : channel_distance_(CalculateChannelDistance(display)), |
- snap_scroll_mode_(SNAP_NONE), |
- first_touch_x_(-1), |
- first_touch_y_(-1), |
- distance_x_(0), |
- distance_y_(0) {} |
- |
-SnapScrollController::~SnapScrollController() {} |
- |
-void SnapScrollController::UpdateSnapScrollMode(float distance_x, |
- float distance_y) { |
- if (snap_scroll_mode_ == SNAP_HORIZ || snap_scroll_mode_ == SNAP_VERT) { |
- distance_x_ += std::abs(distance_x); |
- distance_y_ += std::abs(distance_y); |
- if (snap_scroll_mode_ == SNAP_HORIZ) { |
- if (distance_y_ > channel_distance_) { |
- snap_scroll_mode_ = SNAP_NONE; |
- } else if (distance_x_ > channel_distance_) { |
- distance_x_ = 0; |
- distance_y_ = 0; |
- } |
- } else { |
- if (distance_x_ > channel_distance_) { |
- snap_scroll_mode_ = SNAP_NONE; |
- } else if (distance_y_ > channel_distance_) { |
- distance_x_ = 0; |
- distance_y_ = 0; |
- } |
- } |
- } |
+SnapScrollController::~SnapScrollController() { |
} |
-void SnapScrollController::SetSnapScrollingMode( |
+void SnapScrollController::SetSnapScrollMode( |
const MotionEvent& event, |
bool is_scale_gesture_detection_in_progress) { |
switch (event.GetAction()) { |
case MotionEvent::ACTION_DOWN: |
- snap_scroll_mode_ = SNAP_NONE; |
- first_touch_x_ = event.GetX(); |
- first_touch_y_ = event.GetY(); |
+ mode_ = SNAP_PENDING; |
+ down_position_.set_x(event.GetX()); |
+ down_position_.set_y(event.GetY()); |
break; |
- // Set scrolling mode to SNAP_X if scroll towards x-axis exceeds kSnapBound |
- // and movement towards y-axis is trivial. |
- // Set scrolling mode to SNAP_Y if scroll towards y-axis exceeds kSnapBound |
- // and movement towards x-axis is trivial. |
- // Scrolling mode will remain in SNAP_NONE for other conditions. |
- case MotionEvent::ACTION_MOVE: |
- if (!is_scale_gesture_detection_in_progress && |
- snap_scroll_mode_ == SNAP_NONE) { |
- int x_diff = static_cast<int>(std::abs(event.GetX() - first_touch_x_)); |
- int y_diff = static_cast<int>(std::abs(event.GetY() - first_touch_y_)); |
- if (x_diff > kSnapBound && y_diff < kSnapBound) { |
- snap_scroll_mode_ = SNAP_HORIZ; |
- } else if (x_diff < kSnapBound && y_diff > kSnapBound) { |
- snap_scroll_mode_ = SNAP_VERT; |
- } |
+ case MotionEvent::ACTION_MOVE: { |
+ if (is_scale_gesture_detection_in_progress) |
+ break; |
+ |
+ if (mode_ != SNAP_PENDING) |
+ break; |
+ |
+ // Set scrolling mode to SNAP_X if scroll exceeds |snap_bound_| and the |
+ // ratio of x movement to y movement is sufficiently large. Similarly for |
+ // SNAP_Y and y movement. |
+ float dx = std::abs(event.GetX() - down_position_.x()); |
+ float dy = std::abs(event.GetY() - down_position_.y()); |
+ float kMinSnapBound = snap_bound_; |
+ float kMaxSnapBound = snap_bound_ * 2.f; |
+ if (dx * dx + dy * dy > kMinSnapBound * kMinSnapBound) { |
+ if (!dy || (dx / dy > kMinSnapRatio && dy < kMaxSnapBound)) |
+ mode_ = SNAP_HORIZ; |
+ else if (!dx || (dy / dx > kMinSnapRatio && dx < kMaxSnapBound)) |
+ mode_ = SNAP_VERT; |
} |
- break; |
+ |
+ if (mode_ == SNAP_PENDING && dx > kMaxSnapBound && dy > kMaxSnapBound) |
+ mode_ = SNAP_NONE; |
+ } break; |
case MotionEvent::ACTION_UP: |
case MotionEvent::ACTION_CANCEL: |
- first_touch_x_ = -1; |
- first_touch_y_ = -1; |
- distance_x_ = 0; |
- distance_y_ = 0; |
+ down_position_ = gfx::PointF(); |
+ accumulated_distance_ = gfx::Vector2dF(); |
break; |
default: |
break; |
} |
} |
+void SnapScrollController::UpdateSnapScrollMode(float distance_x, |
+ float distance_y) { |
+ if (!IsSnappingScrolls()) |
+ return; |
+ |
+ accumulated_distance_ += |
+ gfx::Vector2dF(std::abs(distance_x), std::abs(distance_y)); |
+ if (mode_ == SNAP_HORIZ) { |
+ if (accumulated_distance_.y() > channel_distance_) |
+ mode_ = SNAP_NONE; |
+ else if (accumulated_distance_.x() > channel_distance_) |
+ accumulated_distance_ = gfx::Vector2dF(); |
+ } else if (mode_ == SNAP_VERT) { |
+ if (accumulated_distance_.x() > channel_distance_) |
+ mode_ = SNAP_NONE; |
+ else if (accumulated_distance_.y() > channel_distance_) |
+ accumulated_distance_ = gfx::Vector2dF(); |
+ } |
+} |
+ |
+bool SnapScrollController::IsSnapVertical() const { |
+ return mode_ == SNAP_VERT; |
+} |
+ |
+bool SnapScrollController::IsSnapHorizontal() const { |
+ return mode_ == SNAP_HORIZ; |
+} |
+ |
+bool SnapScrollController::IsSnappingScrolls() const { |
+ return IsSnapHorizontal() || IsSnapVertical(); |
+} |
+ |
} // namespace ui |