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
CalculateChannelDistance(const gfx::Display & display)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
SnapScrollController(const gfx::Display & display)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
~SnapScrollController()43 SnapScrollController::~SnapScrollController() {}
44
UpdateSnapScrollMode(float distance_x,float distance_y)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
SetSnapScrollingMode(const MotionEvent & event,bool is_scale_gesture_detection_in_progress)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