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

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

Issue 2201853002: Blink handle selection handle visibility (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: default handle visibility should be false Created 4 years, 4 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 #include "base/metrics/user_metrics.h" 10 #include "base/metrics/user_metrics.h"
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after
55 TouchSelectionController::TouchSelectionController( 55 TouchSelectionController::TouchSelectionController(
56 TouchSelectionControllerClient* client, 56 TouchSelectionControllerClient* client,
57 const Config& config) 57 const Config& config)
58 : client_(client), 58 : client_(client),
59 config_(config), 59 config_(config),
60 force_next_update_(false), 60 force_next_update_(false),
61 response_pending_input_event_(INPUT_EVENT_TYPE_NONE), 61 response_pending_input_event_(INPUT_EVENT_TYPE_NONE),
62 start_orientation_(TouchHandleOrientation::UNDEFINED), 62 start_orientation_(TouchHandleOrientation::UNDEFINED),
63 end_orientation_(TouchHandleOrientation::UNDEFINED), 63 end_orientation_(TouchHandleOrientation::UNDEFINED),
64 active_status_(INACTIVE), 64 active_status_(INACTIVE),
65 activate_insertion_automatically_(false),
66 activate_selection_automatically_(false),
67 selection_empty_(false), 65 selection_empty_(false),
68 selection_editable_(false), 66 selection_editable_(false),
69 temporarily_hidden_(false), 67 temporarily_hidden_(false),
70 anchor_drag_to_selection_start_(false), 68 anchor_drag_to_selection_start_(false),
71 longpress_drag_selector_(this), 69 longpress_drag_selector_(this),
72 selection_handle_dragged_(false) { 70 selection_handle_dragged_(false) {
73 DCHECK(client_); 71 DCHECK(client_);
74 } 72 }
75 73
76 TouchSelectionController::~TouchSelectionController() { 74 TouchSelectionController::~TouchSelectionController() {
77 } 75 }
78 76
79 void TouchSelectionController::OnSelectionBoundsChanged( 77 void TouchSelectionController::OnSelectionBoundsChanged(
80 const gfx::SelectionBound& start, 78 const gfx::SelectionBound& start,
81 const gfx::SelectionBound& end) { 79 const gfx::SelectionBound& end) {
82 if (!force_next_update_ && start == start_ && end_ == end) 80 if (!force_next_update_ && start == start_ && end_ == end)
83 return; 81 return;
84 82
85 // Notify if selection bounds have just been established or dissolved. 83 gfx::SelectionBound defaultBound;
86 if (start.type() != gfx::SelectionBound::EMPTY && 84 if (start == defaultBound && end == defaultBound) {
87 start_.type() == gfx::SelectionBound::EMPTY) { 85 DeactivateSelection();
88 client_->OnSelectionEvent(SELECTION_ESTABLISHED); 86 DeactivateInsertion();
89 } else if (start.type() == gfx::SelectionBound::EMPTY && 87 return;
90 start_.type() != gfx::SelectionBound::EMPTY) {
91 client_->OnSelectionEvent(SELECTION_DISSOLVED);
92 } 88 }
93 89
94 // Swap the Handles when the start and end selection points cross each other. 90 // Swap the Handles when the start and end selection points cross each other.
95 if (active_status_ == SELECTION_ACTIVE) { 91 if (active_status_ == SELECTION_ACTIVE) {
96 if ((start_selection_handle_->IsActive() && 92 if ((start_selection_handle_->IsActive() &&
97 end_.edge_bottom() == start.edge_bottom()) || 93 end_.edge_bottom() == start.edge_bottom()) ||
98 (end_selection_handle_->IsActive() && 94 (end_selection_handle_->IsActive() &&
99 end.edge_bottom() == start_.edge_bottom())) { 95 end.edge_bottom() == start_.edge_bottom())) {
100 start_selection_handle_.swap(end_selection_handle_); 96 start_selection_handle_.swap(end_selection_handle_);
101 } 97 }
102 } 98 }
103 99
104 start_ = start; 100 start_ = start;
105 end_ = end; 101 end_ = end;
106 start_orientation_ = ToTouchHandleOrientation(start_.type()); 102 start_orientation_ = ToTouchHandleOrientation(start_.type());
107 end_orientation_ = ToTouchHandleOrientation(end_.type()); 103 end_orientation_ = ToTouchHandleOrientation(end_.type());
108 force_next_update_ = false; 104 force_next_update_ = false;
109 105
110 if (!activate_selection_automatically_ &&
111 !activate_insertion_automatically_) {
112 DCHECK_EQ(INACTIVE, active_status_);
113 DCHECK_EQ(INPUT_EVENT_TYPE_NONE, response_pending_input_event_);
114 return;
115 }
116
117 // Ensure that |response_pending_input_event_| is cleared after the method 106 // Ensure that |response_pending_input_event_| is cleared after the method
118 // completes, while also making its current value available for the duration 107 // completes, while also making its current value available for the duration
119 // of the call. 108 // of the call.
120 InputEventType causal_input_event = response_pending_input_event_; 109 InputEventType causal_input_event = response_pending_input_event_;
121 response_pending_input_event_ = INPUT_EVENT_TYPE_NONE; 110 response_pending_input_event_ = INPUT_EVENT_TYPE_NONE;
122 base::AutoReset<InputEventType> auto_reset_response_pending_input_event( 111 base::AutoReset<InputEventType> auto_reset_response_pending_input_event(
123 &response_pending_input_event_, causal_input_event); 112 &response_pending_input_event_, causal_input_event);
124 113
125 const bool is_selection_dragging = active_status_ == SELECTION_ACTIVE && 114 const bool is_selection_dragging = active_status_ == SELECTION_ACTIVE &&
126 (start_selection_handle_->IsActive() || 115 (start_selection_handle_->IsActive() ||
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after
204 return start_selection_handle_->WillHandleTouchEvent(event); 193 return start_selection_handle_->WillHandleTouchEvent(event);
205 } 194 }
206 return end_selection_handle_->WillHandleTouchEvent(event); 195 return end_selection_handle_->WillHandleTouchEvent(event);
207 } 196 }
208 197
209 return false; 198 return false;
210 } 199 }
211 200
212 bool TouchSelectionController::WillHandleTapEvent(const gfx::PointF& location, 201 bool TouchSelectionController::WillHandleTapEvent(const gfx::PointF& location,
213 int tap_count) { 202 int tap_count) {
214 if (WillHandleTapOrLongPress(location))
215 return true;
216
217 if (tap_count > 1) { 203 if (tap_count > 1) {
218 response_pending_input_event_ = REPEATED_TAP; 204 response_pending_input_event_ = REPEATED_TAP;
219 ShowSelectionHandlesAutomatically();
220 } else { 205 } else {
221 response_pending_input_event_ = TAP; 206 response_pending_input_event_ = TAP;
222 if (active_status_ != SELECTION_ACTIVE)
223 activate_selection_automatically_ = false;
224 } 207 }
225 ShowInsertionHandleAutomatically();
226 if (selection_empty_ && !config_.show_on_tap_for_empty_editable) 208 if (selection_empty_ && !config_.show_on_tap_for_empty_editable)
227 DeactivateInsertion(); 209 DeactivateInsertion();
228 ForceNextUpdateIfInactive(); 210 ForceNextUpdateIfInactive();
229 return false; 211 return false;
230 } 212 }
231 213
232 bool TouchSelectionController::WillHandleLongPressEvent( 214 bool TouchSelectionController::WillHandleLongPressEvent(
233 base::TimeTicks event_time, 215 base::TimeTicks event_time,
234 const gfx::PointF& location) { 216 const gfx::PointF& location) {
235 if (WillHandleTapOrLongPress(location))
236 return true;
237
238 longpress_drag_selector_.OnLongPressEvent(event_time, location); 217 longpress_drag_selector_.OnLongPressEvent(event_time, location);
239 response_pending_input_event_ = LONG_PRESS; 218 response_pending_input_event_ = LONG_PRESS;
240 ShowSelectionHandlesAutomatically();
241 ShowInsertionHandleAutomatically();
242 ForceNextUpdateIfInactive(); 219 ForceNextUpdateIfInactive();
243 return false; 220 return false;
244 } 221 }
245 222
246 void TouchSelectionController::OnScrollBeginEvent() { 223 void TouchSelectionController::OnScrollBeginEvent() {
247 // When there is an active selection, if the user performs a long-press that 224 // When there is an active selection, if the user performs a long-press that
248 // does not trigger a new selection (e.g. a long-press on an empty area) and 225 // does not trigger a new selection (e.g. a long-press on an empty area) and
249 // then scrolls, the scroll will move the selection. In this case we will 226 // then scrolls, the scroll will move the selection. In this case we will
250 // think incorrectly that the selection change was due to the long-press and 227 // think incorrectly that the selection change was due to the long-press and
251 // will activate touch selection and start long-press drag gesture (see 228 // will activate touch selection and start long-press drag gesture (see
252 // ActivateInsertionIfNecessary()). To prevent this, we need to reset the 229 // ActivateInsertionIfNecessary()). To prevent this, we need to reset the
253 // state of touch selection controller and long-press drag selector. 230 // state of touch selection controller and long-press drag selector.
254 // TODO(mohsen): Remove this workaround when we have enough information about 231 // TODO(mohsen): Remove this workaround when we have enough information about
255 // the cause of a selection change (see https://crbug.com/571897). 232 // the cause of a selection change (see https://crbug.com/571897).
256 longpress_drag_selector_.OnScrollBeginEvent(); 233 longpress_drag_selector_.OnScrollBeginEvent();
257 response_pending_input_event_ = INPUT_EVENT_TYPE_NONE; 234 response_pending_input_event_ = INPUT_EVENT_TYPE_NONE;
258 if (active_status_ == INACTIVE) {
259 activate_insertion_automatically_ = false;
260 activate_selection_automatically_ = false;
261 }
262 }
263
264 void TouchSelectionController::AllowShowingFromCurrentSelection() {
265 if (active_status_ != INACTIVE)
266 return;
267
268 activate_selection_automatically_ = true;
269 activate_insertion_automatically_ = true;
270 if (GetStartPosition() != GetEndPosition()) {
271 OnSelectionChanged();
272 } else if (start_orientation_ == TouchHandleOrientation::CENTER &&
273 selection_editable_) {
274 OnInsertionChanged();
275 }
276 } 235 }
277 236
278 void TouchSelectionController::HideAndDisallowShowingAutomatically() { 237 void TouchSelectionController::HideAndDisallowShowingAutomatically() {
279 response_pending_input_event_ = INPUT_EVENT_TYPE_NONE; 238 response_pending_input_event_ = INPUT_EVENT_TYPE_NONE;
280 DeactivateInsertion(); 239 DeactivateInsertion();
281 DeactivateSelection(); 240 DeactivateSelection();
282 activate_insertion_automatically_ = false;
283 activate_selection_automatically_ = false;
284 } 241 }
285 242
286 void TouchSelectionController::SetTemporarilyHidden(bool hidden) { 243 void TouchSelectionController::SetTemporarilyHidden(bool hidden) {
287 if (temporarily_hidden_ == hidden) 244 if (temporarily_hidden_ == hidden)
288 return; 245 return;
289 temporarily_hidden_ = hidden; 246 temporarily_hidden_ = hidden;
290 RefreshHandleVisibility(); 247 RefreshHandleVisibility();
291 } 248 }
292 249
293 void TouchSelectionController::OnSelectionEditable(bool editable) { 250 void TouchSelectionController::OnSelectionEditable(bool editable) {
(...skipping 161 matching lines...) Expand 10 before | Expand all | Expand 10 after
455 } 412 }
456 413
457 gfx::PointF TouchSelectionController::GetSelectionStart() const { 414 gfx::PointF TouchSelectionController::GetSelectionStart() const {
458 return GetStartPosition(); 415 return GetStartPosition();
459 } 416 }
460 417
461 gfx::PointF TouchSelectionController::GetSelectionEnd() const { 418 gfx::PointF TouchSelectionController::GetSelectionEnd() const {
462 return GetEndPosition(); 419 return GetEndPosition();
463 } 420 }
464 421
465 void TouchSelectionController::ShowInsertionHandleAutomatically() {
466 if (activate_insertion_automatically_)
467 return;
468 activate_insertion_automatically_ = true;
469 ForceNextUpdateIfInactive();
470 }
471
472 void TouchSelectionController::ShowSelectionHandlesAutomatically() {
473 if (activate_selection_automatically_)
474 return;
475 activate_selection_automatically_ = true;
476 ForceNextUpdateIfInactive();
477 }
478
479 bool TouchSelectionController::WillHandleTapOrLongPress(
480 const gfx::PointF& location) {
481 // If there is an active selection that was not triggered by a user gesture,
482 // allow showing the handles for that selection if a gesture occurs within
483 // the selection rect. Note that this hit test is at best a crude
484 // approximation, and may swallow taps that actually fall outside the
485 // real selection.
486 if (active_status_ == INACTIVE &&
487 GetStartPosition() != GetEndPosition() &&
488 RectFBetweenSelectionBounds(start_, end_).Contains(location)) {
489 AllowShowingFromCurrentSelection();
490 return true;
491 }
492 return false;
493 }
494
495 void TouchSelectionController::OnInsertionChanged() { 422 void TouchSelectionController::OnInsertionChanged() {
496 DeactivateSelection(); 423 DeactivateSelection();
497 424
498 if ((response_pending_input_event_ == TAP || 425 if ((response_pending_input_event_ == TAP ||
499 response_pending_input_event_ == REPEATED_TAP) && 426 response_pending_input_event_ == REPEATED_TAP) &&
500 selection_empty_ && !config_.show_on_tap_for_empty_editable) { 427 selection_empty_ && !config_.show_on_tap_for_empty_editable) {
501 HideAndDisallowShowingAutomatically(); 428 HideAndDisallowShowingAutomatically();
502 return; 429 return;
503 } 430 }
504 431
505 if (!activate_insertion_automatically_)
506 return;
507
508 const bool activated = ActivateInsertionIfNecessary(); 432 const bool activated = ActivateInsertionIfNecessary();
509 433
510 const TouchHandle::AnimationStyle animation = GetAnimationStyle(!activated); 434 const TouchHandle::AnimationStyle animation = GetAnimationStyle(!activated);
511 insertion_handle_->SetFocus(start_.edge_top(), start_.edge_bottom()); 435 insertion_handle_->SetFocus(start_.edge_top(), start_.edge_bottom());
512 insertion_handle_->SetVisible(GetStartVisible(), animation); 436 insertion_handle_->SetVisible(GetStartVisible(), animation);
513 437
514 UpdateHandleLayoutIfNecessary(); 438 UpdateHandleLayoutIfNecessary();
515 439
516 client_->OnSelectionEvent(activated ? INSERTION_HANDLE_SHOWN 440 client_->OnSelectionEvent(activated ? INSERTION_HANDLE_SHOWN
517 : INSERTION_HANDLE_MOVED); 441 : INSERTION_HANDLE_MOVED);
518 } 442 }
519 443
520 void TouchSelectionController::OnSelectionChanged() { 444 void TouchSelectionController::OnSelectionChanged() {
521 DeactivateInsertion(); 445 DeactivateInsertion();
522 446
523 if (!activate_selection_automatically_)
524 return;
525
526 const bool activated = ActivateSelectionIfNecessary(); 447 const bool activated = ActivateSelectionIfNecessary();
527 448
528 const TouchHandle::AnimationStyle animation = GetAnimationStyle(!activated); 449 const TouchHandle::AnimationStyle animation = GetAnimationStyle(!activated);
529 450
530 start_selection_handle_->SetFocus(start_.edge_top(), start_.edge_bottom()); 451 start_selection_handle_->SetFocus(start_.edge_top(), start_.edge_bottom());
531 end_selection_handle_->SetFocus(end_.edge_top(), end_.edge_bottom()); 452 end_selection_handle_->SetFocus(end_.edge_top(), end_.edge_bottom());
532 453
533 start_selection_handle_->SetOrientation(start_orientation_); 454 start_selection_handle_->SetOrientation(start_orientation_);
534 end_selection_handle_->SetOrientation(end_orientation_); 455 end_selection_handle_->SetOrientation(end_orientation_);
535 456
(...skipping 159 matching lines...) Expand 10 before | Expand all | Expand 10 after
695 base::TimeDelta duration = base::TimeTicks::Now() - selection_start_time_; 616 base::TimeDelta duration = base::TimeTicks::Now() - selection_start_time_;
696 UMA_HISTOGRAM_CUSTOM_TIMES("Event.TouchSelection.WasDraggedDuration", 617 UMA_HISTOGRAM_CUSTOM_TIMES("Event.TouchSelection.WasDraggedDuration",
697 duration, 618 duration,
698 base::TimeDelta::FromMilliseconds(500), 619 base::TimeDelta::FromMilliseconds(500),
699 base::TimeDelta::FromSeconds(60), 620 base::TimeDelta::FromSeconds(60),
700 60); 621 60);
701 } 622 }
702 } 623 }
703 624
704 } // namespace ui 625 } // namespace ui
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698