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 5 #include "ui/events/gesture_detection/snap_scroll_controller.h" 6 7 #include <cmath> 8 9 #include "ui/events/gesture_detection/motion_event.h" 10 #include "ui/gfx/display.h" 11 12 namespace ui { 13 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 19 float CalculateChannelDistance(const gfx::Display& display) { 20 if (display.bounds().IsEmpty()) 21 return kMinSnapChannelDistance; 22 23 float screen_size = 24 std::abs(hypot(static_cast<float>(display.bounds().width()), 25 static_cast<float>(display.bounds().height()))); 26 27 float snap_channel_distance = screen_size * kSnapChannelDipsPerScreenDip; 28 return std::max(kMinSnapChannelDistance, 29 std::min(kMaxSnapChannelDistance, snap_channel_distance)); 30 } 31 32 } // namespace 33 34 35 SnapScrollController::SnapScrollController(const gfx::Display& display) 36 : channel_distance_(CalculateChannelDistance(display)), 37 snap_scroll_mode_(SNAP_NONE), 38 first_touch_x_(-1), 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 } 67 68 void SnapScrollController::SetSnapScrollingMode( 69 const MotionEvent& event, 70 bool is_scale_gesture_detection_in_progress) { 71 switch (event.GetAction()) { 72 case MotionEvent::ACTION_DOWN: 73 snap_scroll_mode_ = SNAP_NONE; 74 first_touch_x_ = event.GetX(); 75 first_touch_y_ = event.GetY(); 76 break; 77 // Set scrolling mode to SNAP_X if scroll towards x-axis exceeds kSnapBound 78 // and movement towards y-axis is trivial. 79 // Set scrolling mode to SNAP_Y if scroll towards y-axis exceeds kSnapBound 80 // and movement towards x-axis is trivial. 81 // Scrolling mode will remain in SNAP_NONE for other conditions. 82 case MotionEvent::ACTION_MOVE: 83 if (!is_scale_gesture_detection_in_progress && 84 snap_scroll_mode_ == SNAP_NONE) { 85 int x_diff = static_cast<int>(std::abs(event.GetX() - first_touch_x_)); 86 int y_diff = static_cast<int>(std::abs(event.GetY() - first_touch_y_)); 87 if (x_diff > kSnapBound && y_diff < kSnapBound) { 88 snap_scroll_mode_ = SNAP_HORIZ; 89 } else if (x_diff < kSnapBound && y_diff > kSnapBound) { 90 snap_scroll_mode_ = SNAP_VERT; 91 } 92 } 93 break; 94 case MotionEvent::ACTION_UP: 95 case MotionEvent::ACTION_CANCEL: 96 first_touch_x_ = -1; 97 first_touch_y_ = -1; 98 distance_x_ = 0; 99 distance_y_ = 0; 100 break; 101 default: 102 break; 103 } 104 } 105 106 } // namespace ui 107