Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(137)

Side by Side Diff: ui/touch_selection/touch_selection_controller.cc

Issue 1087893003: Support longpress drag selection (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Factor out logic Created 5 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "ui/touch_selection/touch_selection_controller.h" 5 #include "ui/touch_selection/touch_selection_controller.h"
6 6
7 #include "base/auto_reset.h" 7 #include "base/auto_reset.h"
8 #include "base/logging.h" 8 #include "base/logging.h"
9 #include "base/metrics/histogram_macros.h" 9 #include "base/metrics/histogram_macros.h"
10 10
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
52 response_pending_input_event_(INPUT_EVENT_TYPE_NONE), 52 response_pending_input_event_(INPUT_EVENT_TYPE_NONE),
53 start_orientation_(TouchHandleOrientation::UNDEFINED), 53 start_orientation_(TouchHandleOrientation::UNDEFINED),
54 end_orientation_(TouchHandleOrientation::UNDEFINED), 54 end_orientation_(TouchHandleOrientation::UNDEFINED),
55 is_insertion_active_(false), 55 is_insertion_active_(false),
56 activate_insertion_automatically_(false), 56 activate_insertion_automatically_(false),
57 is_selection_active_(false), 57 is_selection_active_(false),
58 activate_selection_automatically_(false), 58 activate_selection_automatically_(false),
59 selection_empty_(false), 59 selection_empty_(false),
60 selection_editable_(false), 60 selection_editable_(false),
61 temporarily_hidden_(false), 61 temporarily_hidden_(false),
62 longpress_drag_selector_(this, tap_slop),
62 selection_handle_dragged_(false) { 63 selection_handle_dragged_(false) {
63 DCHECK(client_); 64 DCHECK(client_);
64 } 65 }
65 66
66 TouchSelectionController::~TouchSelectionController() { 67 TouchSelectionController::~TouchSelectionController() {
67 } 68 }
68 69
69 void TouchSelectionController::OnSelectionBoundsChanged( 70 void TouchSelectionController::OnSelectionBoundsChanged(
70 const SelectionBound& start, 71 const SelectionBound& start,
71 const SelectionBound& end) { 72 const SelectionBound& end) {
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
119 if (start_orientation_ == TouchHandleOrientation::CENTER && 120 if (start_orientation_ == TouchHandleOrientation::CENTER &&
120 selection_editable_) { 121 selection_editable_) {
121 OnInsertionChanged(); 122 OnInsertionChanged();
122 return; 123 return;
123 } 124 }
124 125
125 HideAndDisallowShowingAutomatically(); 126 HideAndDisallowShowingAutomatically();
126 } 127 }
127 128
128 bool TouchSelectionController::WillHandleTouchEvent(const MotionEvent& event) { 129 bool TouchSelectionController::WillHandleTouchEvent(const MotionEvent& event) {
130 if (longpress_drag_selector_.WillHandleTouchEvent(event))
131 return true;
132
129 if (is_insertion_active_) { 133 if (is_insertion_active_) {
130 DCHECK(insertion_handle_); 134 DCHECK(insertion_handle_);
131 return insertion_handle_->WillHandleTouchEvent(event); 135 return insertion_handle_->WillHandleTouchEvent(event);
132 } 136 }
133 137
134 if (is_selection_active_) { 138 if (is_selection_active_) {
135 DCHECK(start_selection_handle_); 139 DCHECK(start_selection_handle_);
136 DCHECK(end_selection_handle_); 140 DCHECK(end_selection_handle_);
137 if (start_selection_handle_->is_dragging()) 141 if (start_selection_handle_->is_dragging())
138 return start_selection_handle_->WillHandleTouchEvent(event); 142 return start_selection_handle_->WillHandleTouchEvent(event);
139 143
140 if (end_selection_handle_->is_dragging()) 144 if (end_selection_handle_->is_dragging())
141 return end_selection_handle_->WillHandleTouchEvent(event); 145 return end_selection_handle_->WillHandleTouchEvent(event);
142 146
143 const gfx::PointF event_pos(event.GetX(), event.GetY()); 147 const gfx::PointF event_pos(event.GetX(), event.GetY());
144 if ((event_pos - GetStartPosition()).LengthSquared() <= 148 if ((event_pos - GetStartPosition()).LengthSquared() <=
145 (event_pos - GetEndPosition()).LengthSquared()) 149 (event_pos - GetEndPosition()).LengthSquared())
146 return start_selection_handle_->WillHandleTouchEvent(event); 150 return start_selection_handle_->WillHandleTouchEvent(event);
147 else 151 else
148 return end_selection_handle_->WillHandleTouchEvent(event); 152 return end_selection_handle_->WillHandleTouchEvent(event);
149 } 153 }
150 154
151 return false; 155 return false;
152 } 156 }
153 157
154 void TouchSelectionController::OnLongPressEvent() { 158 void TouchSelectionController::OnLongPressEvent(base::TimeTicks event_time,
159 const gfx::PointF& position) {
160 longpress_drag_selector_.OnLongPressEvent(event_time, position);
155 response_pending_input_event_ = LONG_PRESS; 161 response_pending_input_event_ = LONG_PRESS;
156 ShowSelectionHandlesAutomatically(); 162 ShowSelectionHandlesAutomatically();
157 ShowInsertionHandleAutomatically(); 163 ShowInsertionHandleAutomatically();
158 ResetCachedValuesIfInactive(); 164 ResetCachedValuesIfInactive();
159 } 165 }
160 166
161 void TouchSelectionController::AllowShowingFromCurrentSelection() { 167 void TouchSelectionController::AllowShowingFromCurrentSelection() {
162 if (is_selection_active_ || is_insertion_active_) 168 if (is_selection_active_ || is_insertion_active_)
163 return; 169 return;
164 170
(...skipping 19 matching lines...) Expand all
184 DeactivateInsertion(); 190 DeactivateInsertion();
185 DeactivateSelection(); 191 DeactivateSelection();
186 activate_insertion_automatically_ = false; 192 activate_insertion_automatically_ = false;
187 activate_selection_automatically_ = false; 193 activate_selection_automatically_ = false;
188 } 194 }
189 195
190 void TouchSelectionController::SetTemporarilyHidden(bool hidden) { 196 void TouchSelectionController::SetTemporarilyHidden(bool hidden) {
191 if (temporarily_hidden_ == hidden) 197 if (temporarily_hidden_ == hidden)
192 return; 198 return;
193 temporarily_hidden_ = hidden; 199 temporarily_hidden_ = hidden;
194 200 OnHandleVisibilityOverrideMaybeChanged();
195 TouchHandle::AnimationStyle animation_style = GetAnimationStyle(true);
196 if (is_selection_active_) {
197 start_selection_handle_->SetVisible(GetStartVisible(), animation_style);
198 end_selection_handle_->SetVisible(GetEndVisible(), animation_style);
199 }
200 if (is_insertion_active_)
201 insertion_handle_->SetVisible(GetStartVisible(), animation_style);
202 } 201 }
203 202
204 void TouchSelectionController::OnSelectionEditable(bool editable) { 203 void TouchSelectionController::OnSelectionEditable(bool editable) {
205 if (selection_editable_ == editable) 204 if (selection_editable_ == editable)
206 return; 205 return;
207 selection_editable_ = editable; 206 selection_editable_ = editable;
208 ResetCachedValuesIfInactive(); 207 ResetCachedValuesIfInactive();
209 if (!selection_editable_) 208 if (!selection_editable_)
210 DeactivateInsertion(); 209 DeactivateInsertion();
211 } 210 }
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after
262 } 261 }
263 262
264 const gfx::PointF& TouchSelectionController::GetStartPosition() const { 263 const gfx::PointF& TouchSelectionController::GetStartPosition() const {
265 return start_.edge_bottom(); 264 return start_.edge_bottom();
266 } 265 }
267 266
268 const gfx::PointF& TouchSelectionController::GetEndPosition() const { 267 const gfx::PointF& TouchSelectionController::GetEndPosition() const {
269 return end_.edge_bottom(); 268 return end_.edge_bottom();
270 } 269 }
271 270
272 void TouchSelectionController::OnHandleDragBegin(const TouchHandle& handle) { 271 void TouchSelectionController::OnDragBegin(
273 if (&handle == insertion_handle_.get()) { 272 const TouchSelectionDraggable& draggable,
273 const gfx::PointF& drag_position) {
274 OnHandleVisibilityOverrideMaybeChanged();
275
276 if (&draggable == insertion_handle_.get()) {
274 client_->OnSelectionEvent(INSERTION_DRAG_STARTED); 277 client_->OnSelectionEvent(INSERTION_DRAG_STARTED);
278 drag_line_offset_ = GetStartLineOffset();
275 return; 279 return;
276 } 280 }
277 281
278 gfx::PointF base, extent; 282 DCHECK(is_selection_active_);
279 if (&handle == start_selection_handle_.get()) { 283
280 base = end_selection_handle_->position() + GetEndLineOffset(); 284 gfx::PointF base = GetStartPosition() + GetStartLineOffset();
281 extent = start_selection_handle_->position() + GetStartLineOffset(); 285 gfx::PointF extent = GetEndPosition() + GetEndLineOffset();
286 if (&draggable == start_selection_handle_.get()) {
287 std::swap(base, extent);
288 drag_line_offset_ = GetStartLineOffset();
289 } else if (&draggable == end_selection_handle_.get()) {
290 drag_line_offset_ = GetEndLineOffset();
282 } else { 291 } else {
283 base = start_selection_handle_->position() + GetStartLineOffset(); 292 DCHECK_EQ(&draggable, &longpress_drag_selector_);
284 extent = end_selection_handle_->position() + GetEndLineOffset(); 293 if ((drag_position - GetStartPosition()).LengthSquared() <
mfomitchev 2015/04/23 21:05:53 Can we just pass an enum in OnDragBegin indicating
jdduke (slow) 2015/04/27 20:24:25 The problem is that the TouchHandle has no awarene
mfomitchev 2015/04/28 02:17:30 Yeah, I was implying we'd pass the type to the Tou
294 (drag_position - GetEndPosition()).LengthSquared()) {
295 std::swap(base, extent);
296 drag_line_offset_ = GetStartLineOffset();
297 } else {
298 drag_line_offset_ = GetEndLineOffset();
299 }
285 } 300 }
286 selection_handle_dragged_ = true; 301 selection_handle_dragged_ = true;
287 302
288 // When moving the handle we want to move only the extent point. Before doing 303 // When moving the handle we want to move only the extent point. Before doing
289 // so we must make sure that the base point is set correctly. 304 // so we must make sure that the base point is set correctly.
290 client_->SelectBetweenCoordinates(base, extent); 305 client_->SelectBetweenCoordinates(base, extent);
291 client_->OnSelectionEvent(SELECTION_DRAG_STARTED); 306 client_->OnSelectionEvent(SELECTION_DRAG_STARTED);
292 } 307 }
293 308
294 void TouchSelectionController::OnHandleDragUpdate(const TouchHandle& handle, 309 void TouchSelectionController::OnDragUpdate(
295 const gfx::PointF& position) { 310 const TouchSelectionDraggable& draggable,
311 const gfx::PointF& drag_position) {
296 // As the position corresponds to the bottom left point of the selection 312 // As the position corresponds to the bottom left point of the selection
297 // bound, offset it by half the corresponding line height. 313 // bound, offset it by half the corresponding line height.
298 gfx::Vector2dF line_offset = &handle == start_selection_handle_.get() 314 gfx::PointF line_position = drag_position + drag_line_offset_;
299 ? GetStartLineOffset() 315 if (&draggable == insertion_handle_.get()) {
300 : GetEndLineOffset();
301 gfx::PointF line_position = position + line_offset;
302 if (&handle == insertion_handle_.get()) {
303 client_->MoveCaret(line_position); 316 client_->MoveCaret(line_position);
304 } else { 317 } else {
305 client_->MoveRangeSelectionExtent(line_position); 318 client_->MoveRangeSelectionExtent(line_position);
306 } 319 }
307 } 320 }
308 321
309 void TouchSelectionController::OnHandleDragEnd(const TouchHandle& handle) { 322 void TouchSelectionController::OnDragEnd(
310 if (&handle == insertion_handle_.get()) 323 const TouchSelectionDraggable& draggable) {
324 OnHandleVisibilityOverrideMaybeChanged();
325 if (&draggable == insertion_handle_.get())
311 client_->OnSelectionEvent(INSERTION_DRAG_STOPPED); 326 client_->OnSelectionEvent(INSERTION_DRAG_STOPPED);
312 else 327 else
313 client_->OnSelectionEvent(SELECTION_DRAG_STOPPED); 328 client_->OnSelectionEvent(SELECTION_DRAG_STOPPED);
314 } 329 }
315 330
316 void TouchSelectionController::OnHandleTapped(const TouchHandle& handle) { 331 void TouchSelectionController::OnHandleTapped(const TouchHandle& handle) {
317 if (insertion_handle_ && &handle == insertion_handle_.get()) 332 if (insertion_handle_ && &handle == insertion_handle_.get())
318 client_->OnSelectionEvent(INSERTION_TAPPED); 333 client_->OnSelectionEvent(INSERTION_TAPPED);
319 } 334 }
320 335
(...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after
437 // intervening SELECTION_CLEARED update to avoid unnecessary state changes. 452 // intervening SELECTION_CLEARED update to avoid unnecessary state changes.
438 if (!is_selection_active_ || response_pending_input_event_ == LONG_PRESS) { 453 if (!is_selection_active_ || response_pending_input_event_ == LONG_PRESS) {
439 if (is_selection_active_) { 454 if (is_selection_active_) {
440 // The active selection session finishes with the start of the new one. 455 // The active selection session finishes with the start of the new one.
441 LogSelectionEnd(); 456 LogSelectionEnd();
442 } 457 }
443 is_selection_active_ = true; 458 is_selection_active_ = true;
444 selection_handle_dragged_ = false; 459 selection_handle_dragged_ = false;
445 selection_start_time_ = base::TimeTicks::Now(); 460 selection_start_time_ = base::TimeTicks::Now();
446 response_pending_input_event_ = INPUT_EVENT_TYPE_NONE; 461 response_pending_input_event_ = INPUT_EVENT_TYPE_NONE;
462 longpress_drag_selector_.OnSelectionActivated(GetStartPosition(),
463 GetEndPosition());
447 client_->OnSelectionEvent(SELECTION_SHOWN); 464 client_->OnSelectionEvent(SELECTION_SHOWN);
448 } 465 }
449 } 466 }
450 467
451 void TouchSelectionController::DeactivateSelection() { 468 void TouchSelectionController::DeactivateSelection() {
452 if (!is_selection_active_) 469 if (!is_selection_active_)
453 return; 470 return;
454 DCHECK(start_selection_handle_); 471 DCHECK(start_selection_handle_);
455 DCHECK(end_selection_handle_); 472 DCHECK(end_selection_handle_);
456 LogSelectionEnd(); 473 LogSelectionEnd();
474 longpress_drag_selector_.OnSelectionDeactivated();
457 start_selection_handle_->SetEnabled(false); 475 start_selection_handle_->SetEnabled(false);
458 end_selection_handle_->SetEnabled(false); 476 end_selection_handle_->SetEnabled(false);
459 is_selection_active_ = false; 477 is_selection_active_ = false;
460 client_->OnSelectionEvent(SELECTION_CLEARED); 478 client_->OnSelectionEvent(SELECTION_CLEARED);
461 } 479 }
462 480
463 void TouchSelectionController::ResetCachedValuesIfInactive() { 481 void TouchSelectionController::ResetCachedValuesIfInactive() {
464 if (is_selection_active_ || is_insertion_active_) 482 if (is_selection_active_ || is_insertion_active_)
465 return; 483 return;
466 start_ = SelectionBound(); 484 start_ = SelectionBound();
467 end_ = SelectionBound(); 485 end_ = SelectionBound();
468 start_orientation_ = TouchHandleOrientation::UNDEFINED; 486 start_orientation_ = TouchHandleOrientation::UNDEFINED;
469 end_orientation_ = TouchHandleOrientation::UNDEFINED; 487 end_orientation_ = TouchHandleOrientation::UNDEFINED;
470 } 488 }
471 489
490 void TouchSelectionController::OnHandleVisibilityOverrideMaybeChanged() {
mfomitchev 2015/04/23 21:05:53 Can we call this something like UpdateHandleVisibi
jdduke (slow) 2015/04/27 20:24:25 Done.
491 TouchHandle::AnimationStyle animation_style = GetAnimationStyle(true);
492 if (is_selection_active_) {
493 start_selection_handle_->SetVisible(GetStartVisible(), animation_style);
494 end_selection_handle_->SetVisible(GetEndVisible(), animation_style);
495 }
496 if (is_insertion_active_)
497 insertion_handle_->SetVisible(GetStartVisible(), animation_style);
498 }
499
472 gfx::Vector2dF TouchSelectionController::GetStartLineOffset() const { 500 gfx::Vector2dF TouchSelectionController::GetStartLineOffset() const {
473 return ComputeLineOffsetFromBottom(start_); 501 return ComputeLineOffsetFromBottom(start_);
474 } 502 }
475 503
476 gfx::Vector2dF TouchSelectionController::GetEndLineOffset() const { 504 gfx::Vector2dF TouchSelectionController::GetEndLineOffset() const {
477 return ComputeLineOffsetFromBottom(end_); 505 return ComputeLineOffsetFromBottom(end_);
478 } 506 }
479 507
480 bool TouchSelectionController::GetStartVisible() const { 508 bool TouchSelectionController::GetStartVisible() const {
481 return start_.visible() && !temporarily_hidden_; 509 if (!start_.visible())
510 return false;
511
512 return !temporarily_hidden_ && !longpress_drag_selector_.IsActive();
482 } 513 }
483 514
484 bool TouchSelectionController::GetEndVisible() const { 515 bool TouchSelectionController::GetEndVisible() const {
485 return end_.visible() && !temporarily_hidden_; 516 if (!end_.visible())
517 return false;
518
519 return !temporarily_hidden_ && !longpress_drag_selector_.IsActive();
486 } 520 }
487 521
488 TouchHandle::AnimationStyle TouchSelectionController::GetAnimationStyle( 522 TouchHandle::AnimationStyle TouchSelectionController::GetAnimationStyle(
489 bool was_active) const { 523 bool was_active) const {
490 return was_active && client_->SupportsAnimation() 524 return was_active && client_->SupportsAnimation()
491 ? TouchHandle::ANIMATION_SMOOTH 525 ? TouchHandle::ANIMATION_SMOOTH
492 : TouchHandle::ANIMATION_NONE; 526 : TouchHandle::ANIMATION_NONE;
493 } 527 }
494 528
495 void TouchSelectionController::LogSelectionEnd() { 529 void TouchSelectionController::LogSelectionEnd() {
496 // TODO(mfomitchev): Once we are able to tell the difference between 530 // TODO(mfomitchev): Once we are able to tell the difference between
497 // 'successful' and 'unsuccessful' selections - log 531 // 'successful' and 'unsuccessful' selections - log
498 // Event.TouchSelection.Duration instead and get rid of 532 // Event.TouchSelection.Duration instead and get rid of
499 // Event.TouchSelectionD.WasDraggeduration. 533 // Event.TouchSelectionD.WasDraggeduration.
500 if (selection_handle_dragged_) { 534 if (selection_handle_dragged_) {
501 base::TimeDelta duration = base::TimeTicks::Now() - selection_start_time_; 535 base::TimeDelta duration = base::TimeTicks::Now() - selection_start_time_;
502 UMA_HISTOGRAM_CUSTOM_TIMES("Event.TouchSelection.WasDraggedDuration", 536 UMA_HISTOGRAM_CUSTOM_TIMES("Event.TouchSelection.WasDraggedDuration",
503 duration, 537 duration,
504 base::TimeDelta::FromMilliseconds(500), 538 base::TimeDelta::FromMilliseconds(500),
505 base::TimeDelta::FromSeconds(60), 539 base::TimeDelta::FromSeconds(60),
506 60); 540 60);
507 } 541 }
508 } 542 }
509 543
510 } // namespace ui 544 } // namespace ui
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698