snap_scroll_controller.cc revision a1401311d1ab56c4ed0a474bd38c108f75cb0cd9
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 11namespace ui { 12namespace { 13const int kSnapBound = 16; 14} // namespace 15 16SnapScrollController::Config::Config() 17 : screen_width_pixels(1), screen_height_pixels(1), device_scale_factor(1) {} 18 19SnapScrollController::Config::~Config() {} 20 21SnapScrollController::SnapScrollController(const Config& config) 22 : channel_distance_(CalculateChannelDistance(config)), 23 snap_scroll_mode_(SNAP_NONE), 24 first_touch_x_(-1), 25 first_touch_y_(-1), 26 distance_x_(0), 27 distance_y_(0) {} 28 29SnapScrollController::~SnapScrollController() {} 30 31void SnapScrollController::UpdateSnapScrollMode(float distance_x, 32 float distance_y) { 33 if (snap_scroll_mode_ == SNAP_HORIZ || snap_scroll_mode_ == SNAP_VERT) { 34 distance_x_ += std::abs(distance_x); 35 distance_y_ += std::abs(distance_y); 36 if (snap_scroll_mode_ == SNAP_HORIZ) { 37 if (distance_y_ > channel_distance_) { 38 snap_scroll_mode_ = SNAP_NONE; 39 } else if (distance_x_ > channel_distance_) { 40 distance_x_ = 0; 41 distance_y_ = 0; 42 } 43 } else { 44 if (distance_x_ > channel_distance_) { 45 snap_scroll_mode_ = SNAP_NONE; 46 } else if (distance_y_ > channel_distance_) { 47 distance_x_ = 0; 48 distance_y_ = 0; 49 } 50 } 51 } 52} 53 54void SnapScrollController::SetSnapScrollingMode( 55 const MotionEvent& event, 56 bool is_scale_gesture_detection_in_progress) { 57 switch (event.GetAction()) { 58 case MotionEvent::ACTION_DOWN: 59 snap_scroll_mode_ = SNAP_NONE; 60 first_touch_x_ = event.GetX(); 61 first_touch_y_ = event.GetY(); 62 break; 63 // Set scrolling mode to SNAP_X if scroll towards x-axis exceeds kSnapBound 64 // and movement towards y-axis is trivial. 65 // Set scrolling mode to SNAP_Y if scroll towards y-axis exceeds kSnapBound 66 // and movement towards x-axis is trivial. 67 // Scrolling mode will remain in SNAP_NONE for other conditions. 68 case MotionEvent::ACTION_MOVE: 69 if (!is_scale_gesture_detection_in_progress && 70 snap_scroll_mode_ == SNAP_NONE) { 71 int x_diff = static_cast<int>(std::abs(event.GetX() - first_touch_x_)); 72 int y_diff = static_cast<int>(std::abs(event.GetY() - first_touch_y_)); 73 if (x_diff > kSnapBound && y_diff < kSnapBound) { 74 snap_scroll_mode_ = SNAP_HORIZ; 75 } else if (x_diff < kSnapBound && y_diff > kSnapBound) { 76 snap_scroll_mode_ = SNAP_VERT; 77 } 78 } 79 break; 80 case MotionEvent::ACTION_UP: 81 case MotionEvent::ACTION_CANCEL: 82 first_touch_x_ = -1; 83 first_touch_y_ = -1; 84 distance_x_ = 0; 85 distance_y_ = 0; 86 break; 87 default: 88 break; 89 } 90} 91 92// static 93float SnapScrollController::CalculateChannelDistance(const Config& config) { 94 float channel_distance = 16.f; 95 96 const float screen_size = std::abs( 97 hypot((float)config.screen_width_pixels / config.device_scale_factor, 98 (float)config.screen_height_pixels / config.device_scale_factor)); 99 if (screen_size < 3.f) { 100 channel_distance = 16.f; 101 } else if (screen_size < 5.f) { 102 channel_distance = 22.f; 103 } else if (screen_size < 7.f) { 104 channel_distance = 28.f; 105 } else { 106 channel_distance = 34.f; 107 } 108 channel_distance = channel_distance * config.device_scale_factor; 109 if (channel_distance < 16.f) 110 channel_distance = 16.f; 111 112 return channel_distance; 113} 114 115} // namespace ui 116