Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright 2015 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/touch_selection/longpress_drag_selector.h" | |
| 6 | |
| 7 #include "ui/events/gesture_detection/motion_event.h" | |
| 8 | |
| 9 namespace ui { | |
| 10 namespace { | |
| 11 | |
| 12 const int kLongPressTimeEpsilonMicros = 10; | |
| 13 | |
| 14 } // namespace | |
| 15 | |
| 16 LongPressDragSelector::LongPressDragSelector( | |
| 17 TouchSelectionDraggableClient* client, | |
| 18 float slop_length) | |
| 19 : client_(client), slop_length_(slop_length), state_(INACTIVE) { | |
| 20 } | |
| 21 | |
| 22 LongPressDragSelector::~LongPressDragSelector() { | |
| 23 } | |
| 24 | |
| 25 bool LongPressDragSelector::WillHandleTouchEvent(const MotionEvent& event) { | |
| 26 switch (event.GetAction()) { | |
| 27 case MotionEvent::ACTION_DOWN: | |
| 28 touch_down_position_.SetPoint(event.GetX(), event.GetY()); | |
| 29 touch_down_time_ = event.GetEventTime(); | |
| 30 longpress_drag_start_position_ = gfx::PointF(); | |
| 31 SetState(LONGPRESS_PENDING); | |
| 32 return false; | |
| 33 | |
| 34 case MotionEvent::ACTION_UP: | |
| 35 case MotionEvent::ACTION_CANCEL: | |
| 36 SetState(INACTIVE); | |
| 37 return false; | |
| 38 | |
| 39 case MotionEvent::ACTION_MOVE: | |
| 40 break; | |
| 41 | |
| 42 default: | |
| 43 return false; | |
| 44 } | |
| 45 | |
| 46 if (state_ != DRAG_PENDING && state_ != DRAGGING) | |
| 47 return false; | |
| 48 | |
| 49 gfx::PointF position(event.GetX(), event.GetY()); | |
| 50 if (state_ == DRAGGING) { | |
| 51 gfx::PointF drag_position = position + longpress_drag_selection_offset_; | |
| 52 client_->OnDragUpdate(*this, drag_position); | |
| 53 return true; | |
| 54 } | |
| 55 | |
| 56 // We can't use |touch_down_position_| as the offset anchor, as | |
| 57 // showing the selection UI may have shifted the motion coordinates. | |
| 58 if (longpress_drag_start_position_.IsOrigin()) { | |
| 59 longpress_drag_start_position_ = position; | |
| 60 return true; | |
| 61 } | |
| 62 | |
| 63 // Allow an additional slop affordance after the longpress occurs. | |
| 64 gfx::Vector2dF delta = position - longpress_drag_start_position_; | |
| 65 if (delta.LengthSquared() < (slop_length_ * slop_length_)) | |
| 66 return true; | |
| 67 | |
| 68 gfx::PointF base = selection_start_; | |
| 69 gfx::PointF extent = selection_end_; | |
| 70 if (std::abs(delta.y()) > std::abs(delta.x())) { | |
| 71 // If initial motion is upward, extend the starting selection bound. | |
|
mfomitchev
2015/04/23 21:05:53
By the similar logic, wouldn't we want to extend t
jdduke (slow)
2015/04/27 20:24:25
We do, the exceptional case is dragging 'backward'
mfomitchev
2015/04/28 02:17:30
Ah, right, I misread the code.
| |
| 72 if (delta.y() < 0) | |
| 73 std::swap(base, extent); | |
| 74 } else { | |
| 75 // Otherwise extend the selection bound toward which we're moving. | |
| 76 gfx::Vector2dF start_delta = selection_start_ - position; | |
| 77 if (!start_delta.IsZero()) | |
| 78 start_delta.Scale(1.f / start_delta.Length()); | |
| 79 gfx::Vector2dF end_delta = selection_end_ - position; | |
| 80 if (!end_delta.IsZero()) | |
| 81 end_delta.Scale(1.f / start_delta.Length()); | |
| 82 if (gfx::DotProduct(start_delta, delta) > | |
|
mfomitchev
2015/04/23 21:05:53
Heh. Smart.
Long-press is going to select a single
jdduke (slow)
2015/04/27 20:24:25
Yeah, without awareness of text direction, making
mfomitchev
2015/04/28 02:17:30
We can already make the decision based on whether
jdduke (slow)
2015/04/28 20:37:48
Hmm, yeah, the math isn't quite as clear.
That s
| |
| 83 gfx::DotProduct(end_delta, delta)) { | |
| 84 std::swap(base, extent); | |
| 85 } | |
| 86 } | |
| 87 longpress_drag_selection_offset_ = extent - position; | |
| 88 client_->OnDragBegin(*this, extent); | |
| 89 SetState(DRAGGING); | |
| 90 return true; | |
| 91 } | |
| 92 | |
| 93 void LongPressDragSelector::OnLongPressEvent(base::TimeTicks event_time, | |
| 94 const gfx::PointF& position) { | |
| 95 // We have no guarantees that the current gesture stream is aligned with the | |
| 96 // observed touch stream. We only know that the gesture sequence is downstream | |
| 97 // from the touch sequence. Using a time/distance heuristic helps ensure that | |
| 98 // the observed longpress corresponds to the active touch sequence. | |
| 99 if (state_ == LONGPRESS_PENDING && | |
| 100 // Use a small time epsilon to account for floating point time conversion. | |
| 101 (touch_down_time_ - event_time) < | |
| 102 base::TimeDelta::FromMicroseconds(kLongPressTimeEpsilonMicros) && | |
| 103 ((touch_down_position_ - position).LengthSquared() < | |
| 104 (slop_length_ * slop_length_))) { | |
| 105 SetState(SELECTION_PENDING); | |
| 106 } | |
| 107 } | |
| 108 | |
| 109 void LongPressDragSelector::OnSelectionActivated(const gfx::PointF& start, | |
| 110 const gfx::PointF& end) { | |
| 111 if (state_ == SELECTION_PENDING) { | |
| 112 SetState(DRAG_PENDING); | |
| 113 selection_start_ = start; | |
| 114 selection_end_ = end; | |
| 115 } | |
| 116 } | |
| 117 | |
| 118 void LongPressDragSelector::OnSelectionDeactivated() { | |
| 119 SetState(INACTIVE); | |
| 120 } | |
| 121 | |
| 122 bool LongPressDragSelector::IsActive() const { | |
|
mfomitchev
2015/04/23 21:05:53
This is similar to is_dragging() in TouchHandle. P
jdduke (slow)
2015/04/27 20:24:25
Hmm, the current result would be slightly misleadi
mfomitchev
2015/04/28 02:17:30
Sorry, I should've clarified my comment. I was sug
jdduke (slow)
2015/04/28 20:37:48
IsActive() sounds good to me.
| |
| 123 return state_ != INACTIVE && state_ != LONGPRESS_PENDING; | |
| 124 } | |
| 125 | |
| 126 void LongPressDragSelector::SetState(SelectionState state) { | |
| 127 if (state_ == state) | |
| 128 return; | |
| 129 | |
| 130 const bool was_dragging = state_ == DRAGGING; | |
| 131 state_ = state; | |
| 132 | |
| 133 // TODO(jdduke): Add UMA for tracking relative longpress drag frequency. | |
| 134 if (was_dragging) | |
| 135 client_->OnDragEnd(*this); | |
| 136 } | |
| 137 | |
| 138 } // namespace ui | |
| OLD | NEW |