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

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: fixing aura problems 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,
80 bool is_handle_visible) {
82 if (!force_next_update_ && start == start_ && end_ == end) 81 if (!force_next_update_ && start == start_ && end_ == end)
83 return; 82 return;
84 83
85 // Notify if selection bounds have just been established or dissolved. 84 // Notify if selection bounds have just been established or dissolved.
86 if (start.type() != gfx::SelectionBound::EMPTY && 85 if (start.type() != gfx::SelectionBound::EMPTY &&
87 start_.type() == gfx::SelectionBound::EMPTY) { 86 start_.type() == gfx::SelectionBound::EMPTY) {
88 client_->OnSelectionEvent(SELECTION_ESTABLISHED); 87 client_->OnSelectionEvent(SELECTION_ESTABLISHED);
89 } else if (start.type() == gfx::SelectionBound::EMPTY && 88 } else if (start.type() == gfx::SelectionBound::EMPTY &&
90 start_.type() != gfx::SelectionBound::EMPTY) { 89 start_.type() != gfx::SelectionBound::EMPTY) {
91 client_->OnSelectionEvent(SELECTION_DISSOLVED); 90 client_->OnSelectionEvent(SELECTION_DISSOLVED);
92 } 91 }
93 92
94 // Swap the Handles when the start and end selection points cross each other. 93 // Swap the Handles when the start and end selection points cross each other.
95 if (active_status_ == SELECTION_ACTIVE) { 94 if (active_status_ == SELECTION_ACTIVE) {
96 if ((start_selection_handle_->IsActive() && 95 if ((start_selection_handle_->IsActive() &&
97 end_.edge_bottom() == start.edge_bottom()) || 96 end_.edge_bottom() == start.edge_bottom()) ||
98 (end_selection_handle_->IsActive() && 97 (end_selection_handle_->IsActive() &&
99 end.edge_bottom() == start_.edge_bottom())) { 98 end.edge_bottom() == start_.edge_bottom())) {
100 start_selection_handle_.swap(end_selection_handle_); 99 start_selection_handle_.swap(end_selection_handle_);
101 } 100 }
102 } 101 }
103 102
104 start_ = start; 103 start_ = start;
105 end_ = end; 104 end_ = end;
106 start_orientation_ = ToTouchHandleOrientation(start_.type()); 105 start_orientation_ = ToTouchHandleOrientation(start_.type());
107 end_orientation_ = ToTouchHandleOrientation(end_.type()); 106 end_orientation_ = ToTouchHandleOrientation(end_.type());
108 force_next_update_ = false; 107 force_next_update_ = false;
109 108
110 if (!activate_selection_automatically_ && 109 if (!is_handle_visible) {
111 !activate_insertion_automatically_) { 110 DeactivateSelection();
112 DCHECK_EQ(INACTIVE, active_status_); 111 DeactivateInsertion();
113 DCHECK_EQ(INPUT_EVENT_TYPE_NONE, response_pending_input_event_);
114 return; 112 return;
115 } 113 }
116 114
117 // Ensure that |response_pending_input_event_| is cleared after the method 115 // Ensure that |response_pending_input_event_| is cleared after the method
118 // completes, while also making its current value available for the duration 116 // completes, while also making its current value available for the duration
119 // of the call. 117 // of the call.
120 InputEventType causal_input_event = response_pending_input_event_; 118 InputEventType causal_input_event = response_pending_input_event_;
121 response_pending_input_event_ = INPUT_EVENT_TYPE_NONE; 119 response_pending_input_event_ = INPUT_EVENT_TYPE_NONE;
122 base::AutoReset<InputEventType> auto_reset_response_pending_input_event( 120 base::AutoReset<InputEventType> auto_reset_response_pending_input_event(
123 &response_pending_input_event_, causal_input_event); 121 &response_pending_input_event_, causal_input_event);
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after
204 return start_selection_handle_->WillHandleTouchEvent(event); 202 return start_selection_handle_->WillHandleTouchEvent(event);
205 } 203 }
206 return end_selection_handle_->WillHandleTouchEvent(event); 204 return end_selection_handle_->WillHandleTouchEvent(event);
207 } 205 }
208 206
209 return false; 207 return false;
210 } 208 }
211 209
212 bool TouchSelectionController::WillHandleTapEvent(const gfx::PointF& location, 210 bool TouchSelectionController::WillHandleTapEvent(const gfx::PointF& location,
213 int tap_count) { 211 int tap_count) {
214 if (WillHandleTapOrLongPress(location))
215 return true;
216
217 if (tap_count > 1) { 212 if (tap_count > 1) {
218 response_pending_input_event_ = REPEATED_TAP; 213 response_pending_input_event_ = REPEATED_TAP;
219 ShowSelectionHandlesAutomatically();
220 } else { 214 } else {
221 response_pending_input_event_ = TAP; 215 response_pending_input_event_ = TAP;
222 if (active_status_ != SELECTION_ACTIVE)
223 activate_selection_automatically_ = false;
224 } 216 }
225 ShowInsertionHandleAutomatically();
226 if (selection_empty_ && !config_.show_on_tap_for_empty_editable) 217 if (selection_empty_ && !config_.show_on_tap_for_empty_editable)
227 DeactivateInsertion(); 218 DeactivateInsertion();
228 ForceNextUpdateIfInactive(); 219 ForceNextUpdateIfInactive();
229 return false; 220 return false;
230 } 221 }
231 222
232 bool TouchSelectionController::WillHandleLongPressEvent( 223 bool TouchSelectionController::WillHandleLongPressEvent(
233 base::TimeTicks event_time, 224 base::TimeTicks event_time,
234 const gfx::PointF& location) { 225 const gfx::PointF& location) {
235 if (WillHandleTapOrLongPress(location))
236 return true;
237
238 longpress_drag_selector_.OnLongPressEvent(event_time, location); 226 longpress_drag_selector_.OnLongPressEvent(event_time, location);
239 response_pending_input_event_ = LONG_PRESS; 227 response_pending_input_event_ = LONG_PRESS;
240 ShowSelectionHandlesAutomatically();
241 ShowInsertionHandleAutomatically();
242 ForceNextUpdateIfInactive(); 228 ForceNextUpdateIfInactive();
243 return false; 229 return false;
244 } 230 }
245 231
246 void TouchSelectionController::OnScrollBeginEvent() { 232 void TouchSelectionController::OnScrollBeginEvent() {
247 // When there is an active selection, if the user performs a long-press that 233 // 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 234 // 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 235 // 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 236 // 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 237 // will activate touch selection and start long-press drag gesture (see
252 // ActivateInsertionIfNecessary()). To prevent this, we need to reset the 238 // ActivateInsertionIfNecessary()). To prevent this, we need to reset the
253 // state of touch selection controller and long-press drag selector. 239 // state of touch selection controller and long-press drag selector.
254 // TODO(mohsen): Remove this workaround when we have enough information about 240 // TODO(mohsen): Remove this workaround when we have enough information about
255 // the cause of a selection change (see https://crbug.com/571897). 241 // the cause of a selection change (see https://crbug.com/571897).
256 longpress_drag_selector_.OnScrollBeginEvent(); 242 longpress_drag_selector_.OnScrollBeginEvent();
257 response_pending_input_event_ = INPUT_EVENT_TYPE_NONE; 243 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 } 244 }
277 245
278 void TouchSelectionController::HideAndDisallowShowingAutomatically() { 246 void TouchSelectionController::HideAndDisallowShowingAutomatically() {
279 response_pending_input_event_ = INPUT_EVENT_TYPE_NONE; 247 response_pending_input_event_ = INPUT_EVENT_TYPE_NONE;
280 DeactivateInsertion(); 248 DeactivateInsertion();
281 DeactivateSelection(); 249 DeactivateSelection();
282 activate_insertion_automatically_ = false;
283 activate_selection_automatically_ = false;
284 } 250 }
285 251
286 void TouchSelectionController::SetTemporarilyHidden(bool hidden) { 252 void TouchSelectionController::SetTemporarilyHidden(bool hidden) {
287 if (temporarily_hidden_ == hidden) 253 if (temporarily_hidden_ == hidden)
288 return; 254 return;
289 temporarily_hidden_ = hidden; 255 temporarily_hidden_ = hidden;
290 RefreshHandleVisibility(); 256 RefreshHandleVisibility();
291 } 257 }
292 258
293 void TouchSelectionController::OnSelectionEditable(bool editable) { 259 void TouchSelectionController::OnSelectionEditable(bool editable) {
(...skipping 161 matching lines...) Expand 10 before | Expand all | Expand 10 after
455 } 421 }
456 422
457 gfx::PointF TouchSelectionController::GetSelectionStart() const { 423 gfx::PointF TouchSelectionController::GetSelectionStart() const {
458 return GetStartPosition(); 424 return GetStartPosition();
459 } 425 }
460 426
461 gfx::PointF TouchSelectionController::GetSelectionEnd() const { 427 gfx::PointF TouchSelectionController::GetSelectionEnd() const {
462 return GetEndPosition(); 428 return GetEndPosition();
463 } 429 }
464 430
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() { 431 void TouchSelectionController::OnInsertionChanged() {
496 DeactivateSelection(); 432 DeactivateSelection();
497 433
498 if ((response_pending_input_event_ == TAP || 434 if ((response_pending_input_event_ == TAP ||
499 response_pending_input_event_ == REPEATED_TAP) && 435 response_pending_input_event_ == REPEATED_TAP) &&
500 selection_empty_ && !config_.show_on_tap_for_empty_editable) { 436 selection_empty_ && !config_.show_on_tap_for_empty_editable) {
501 HideAndDisallowShowingAutomatically(); 437 HideAndDisallowShowingAutomatically();
502 return; 438 return;
503 } 439 }
504 440
505 if (!activate_insertion_automatically_)
506 return;
507
508 const bool activated = ActivateInsertionIfNecessary(); 441 const bool activated = ActivateInsertionIfNecessary();
509 442
510 const TouchHandle::AnimationStyle animation = GetAnimationStyle(!activated); 443 const TouchHandle::AnimationStyle animation = GetAnimationStyle(!activated);
511 insertion_handle_->SetFocus(start_.edge_top(), start_.edge_bottom()); 444 insertion_handle_->SetFocus(start_.edge_top(), start_.edge_bottom());
512 insertion_handle_->SetVisible(GetStartVisible(), animation); 445 insertion_handle_->SetVisible(GetStartVisible(), animation);
513 446
514 UpdateHandleLayoutIfNecessary(); 447 UpdateHandleLayoutIfNecessary();
515 448
516 client_->OnSelectionEvent(activated ? INSERTION_HANDLE_SHOWN 449 client_->OnSelectionEvent(activated ? INSERTION_HANDLE_SHOWN
517 : INSERTION_HANDLE_MOVED); 450 : INSERTION_HANDLE_MOVED);
518 } 451 }
519 452
520 void TouchSelectionController::OnSelectionChanged() { 453 void TouchSelectionController::OnSelectionChanged() {
521 DeactivateInsertion(); 454 DeactivateInsertion();
522 455
523 if (!activate_selection_automatically_)
524 return;
525
526 const bool activated = ActivateSelectionIfNecessary(); 456 const bool activated = ActivateSelectionIfNecessary();
527 457
528 const TouchHandle::AnimationStyle animation = GetAnimationStyle(!activated); 458 const TouchHandle::AnimationStyle animation = GetAnimationStyle(!activated);
529 459
530 start_selection_handle_->SetFocus(start_.edge_top(), start_.edge_bottom()); 460 start_selection_handle_->SetFocus(start_.edge_top(), start_.edge_bottom());
531 end_selection_handle_->SetFocus(end_.edge_top(), end_.edge_bottom()); 461 end_selection_handle_->SetFocus(end_.edge_top(), end_.edge_bottom());
532 462
533 start_selection_handle_->SetOrientation(start_orientation_); 463 start_selection_handle_->SetOrientation(start_orientation_);
534 end_selection_handle_->SetOrientation(end_orientation_); 464 end_selection_handle_->SetOrientation(end_orientation_);
535 465
(...skipping 159 matching lines...) Expand 10 before | Expand all | Expand 10 after
695 base::TimeDelta duration = base::TimeTicks::Now() - selection_start_time_; 625 base::TimeDelta duration = base::TimeTicks::Now() - selection_start_time_;
696 UMA_HISTOGRAM_CUSTOM_TIMES("Event.TouchSelection.WasDraggedDuration", 626 UMA_HISTOGRAM_CUSTOM_TIMES("Event.TouchSelection.WasDraggedDuration",
697 duration, 627 duration,
698 base::TimeDelta::FromMilliseconds(500), 628 base::TimeDelta::FromMilliseconds(500),
699 base::TimeDelta::FromSeconds(60), 629 base::TimeDelta::FromSeconds(60),
700 60); 630 60);
701 } 631 }
702 } 632 }
703 633
704 } // namespace ui 634 } // namespace ui
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698