Home | History | Annotate | Download | only in gesture_detection
      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