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

Unified 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: Rebase Created 5 years, 7 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 side-by-side diff with in-line comments
Download patch
Index: ui/touch_selection/touch_selection_controller.cc
diff --git a/ui/touch_selection/touch_selection_controller.cc b/ui/touch_selection/touch_selection_controller.cc
index 3dbaaa008ecd0da64d47dcae6cf703e032b85c4c..a5facdcba480a20084fc5b5cb08e7080aeffd779 100644
--- a/ui/touch_selection/touch_selection_controller.cc
+++ b/ui/touch_selection/touch_selection_controller.cc
@@ -40,16 +40,22 @@ TouchHandleOrientation ToTouchHandleOrientation(SelectionBound::Type type) {
} // namespace
+TouchSelectionController::Config::Config()
+ : tap_timeout(base::TimeDelta::FromMilliseconds(100)),
+ tap_slop(8),
+ enable_longpress_drag_selection(false),
+ show_on_tap_for_empty_editable(false) {
+}
+
+TouchSelectionController::Config::~Config() {
+}
+
TouchSelectionController::TouchSelectionController(
TouchSelectionControllerClient* client,
- base::TimeDelta tap_timeout,
- float tap_slop,
- bool show_on_tap_for_empty_editable)
+ const Config& config)
: client_(client),
- tap_timeout_(tap_timeout),
- tap_slop_(tap_slop),
+ config_(config),
force_next_update_(false),
- show_on_tap_for_empty_editable_(show_on_tap_for_empty_editable),
response_pending_input_event_(INPUT_EVENT_TYPE_NONE),
start_orientation_(TouchHandleOrientation::UNDEFINED),
end_orientation_(TouchHandleOrientation::UNDEFINED),
@@ -59,6 +65,8 @@ TouchSelectionController::TouchSelectionController(
selection_empty_(false),
selection_editable_(false),
temporarily_hidden_(false),
+ anchor_drag_to_selection_start_(false),
+ longpress_drag_selector_(this),
selection_handle_dragged_(false) {
DCHECK(client_);
}
@@ -94,8 +102,8 @@ void TouchSelectionController::OnSelectionBoundsChanged(
&response_pending_input_event_, causal_input_event);
const bool is_selection_dragging = active_status_ == SELECTION_ACTIVE &&
- (start_selection_handle_->is_dragging() ||
- end_selection_handle_->is_dragging());
+ (start_selection_handle_->IsActive() ||
+ end_selection_handle_->IsActive());
// It's possible that the bounds temporarily overlap while a selection handle
// is being dragged, incorrectly reporting a CENTER orientation.
@@ -128,6 +136,11 @@ void TouchSelectionController::OnSelectionBoundsChanged(
}
bool TouchSelectionController::WillHandleTouchEvent(const MotionEvent& event) {
+ if (config_.enable_longpress_drag_selection &&
+ longpress_drag_selector_.WillHandleTouchEvent(event)) {
+ return true;
+ }
+
if (active_status_ == INSERTION_ACTIVE) {
DCHECK(insertion_handle_);
return insertion_handle_->WillHandleTouchEvent(event);
@@ -136,10 +149,10 @@ bool TouchSelectionController::WillHandleTouchEvent(const MotionEvent& event) {
if (active_status_ == SELECTION_ACTIVE) {
DCHECK(start_selection_handle_);
DCHECK(end_selection_handle_);
- if (start_selection_handle_->is_dragging())
+ if (start_selection_handle_->IsActive())
return start_selection_handle_->WillHandleTouchEvent(event);
- if (end_selection_handle_->is_dragging())
+ if (end_selection_handle_->IsActive())
return end_selection_handle_->WillHandleTouchEvent(event);
const gfx::PointF event_pos(event.GetX(), event.GetY());
@@ -161,17 +174,19 @@ bool TouchSelectionController::WillHandleTapEvent(const gfx::PointF& location) {
if (active_status_ != SELECTION_ACTIVE)
activate_selection_automatically_ = false;
ShowInsertionHandleAutomatically();
- if (selection_empty_ && !show_on_tap_for_empty_editable_)
+ if (selection_empty_ && !config_.show_on_tap_for_empty_editable)
DeactivateInsertion();
ForceNextUpdateIfInactive();
return false;
}
bool TouchSelectionController::WillHandleLongPressEvent(
+ base::TimeTicks event_time,
const gfx::PointF& location) {
if (WillHandleTapOrLongPress(location))
return true;
+ longpress_drag_selector_.OnLongPressEvent(event_time, location);
response_pending_input_event_ = LONG_PRESS;
ShowSelectionHandlesAutomatically();
ShowInsertionHandleAutomatically();
@@ -205,14 +220,7 @@ void TouchSelectionController::SetTemporarilyHidden(bool hidden) {
if (temporarily_hidden_ == hidden)
return;
temporarily_hidden_ = hidden;
-
- TouchHandle::AnimationStyle animation_style = GetAnimationStyle(true);
- if (active_status_ == SELECTION_ACTIVE) {
- start_selection_handle_->SetVisible(GetStartVisible(), animation_style);
- end_selection_handle_->SetVisible(GetEndVisible(), animation_style);
- } else if (active_status_ == INSERTION_ACTIVE) {
- insertion_handle_->SetVisible(GetStartVisible(), animation_style);
- }
+ RefreshHandleVisibility();
}
void TouchSelectionController::OnSelectionEditable(bool editable) {
@@ -283,20 +291,34 @@ const gfx::PointF& TouchSelectionController::GetEndPosition() const {
return end_.edge_bottom();
}
-void TouchSelectionController::OnHandleDragBegin(const TouchHandle& handle) {
- if (&handle == insertion_handle_.get()) {
+void TouchSelectionController::OnDragBegin(
+ const TouchSelectionDraggable& draggable,
+ const gfx::PointF& drag_position) {
+ if (&draggable == insertion_handle_.get()) {
+ DCHECK_EQ(active_status_, INSERTION_ACTIVE);
client_->OnSelectionEvent(INSERTION_DRAG_STARTED);
+ anchor_drag_to_selection_start_ = true;
return;
}
- gfx::PointF base, extent;
- if (&handle == start_selection_handle_.get()) {
- base = end_selection_handle_->position() + GetEndLineOffset();
- extent = start_selection_handle_->position() + GetStartLineOffset();
+ DCHECK_EQ(active_status_, SELECTION_ACTIVE);
+
+ if (&draggable == start_selection_handle_.get()) {
+ anchor_drag_to_selection_start_ = true;
+ } else if (&draggable == end_selection_handle_.get()) {
+ anchor_drag_to_selection_start_ = false;
} else {
- base = start_selection_handle_->position() + GetStartLineOffset();
- extent = end_selection_handle_->position() + GetEndLineOffset();
+ DCHECK_EQ(&draggable, &longpress_drag_selector_);
+ anchor_drag_to_selection_start_ =
+ (drag_position - GetStartPosition()).LengthSquared() <
+ (drag_position - GetEndPosition()).LengthSquared();
}
+
+ gfx::PointF base = GetStartPosition() + GetStartLineOffset();
+ gfx::PointF extent = GetEndPosition() + GetEndLineOffset();
+ if (anchor_drag_to_selection_start_)
+ std::swap(base, extent);
+
selection_handle_dragged_ = true;
// When moving the handle we want to move only the extent point. Before doing
@@ -305,27 +327,35 @@ void TouchSelectionController::OnHandleDragBegin(const TouchHandle& handle) {
client_->OnSelectionEvent(SELECTION_DRAG_STARTED);
}
-void TouchSelectionController::OnHandleDragUpdate(const TouchHandle& handle,
- const gfx::PointF& position) {
+void TouchSelectionController::OnDragUpdate(
+ const TouchSelectionDraggable& draggable,
+ const gfx::PointF& drag_position) {
// As the position corresponds to the bottom left point of the selection
- // bound, offset it by half the corresponding line height.
- gfx::Vector2dF line_offset = &handle == start_selection_handle_.get()
+ // bound, offset it to some reasonable point on the current line of text.
+ gfx::Vector2dF line_offset = anchor_drag_to_selection_start_
? GetStartLineOffset()
: GetEndLineOffset();
- gfx::PointF line_position = position + line_offset;
- if (&handle == insertion_handle_.get())
+ gfx::PointF line_position = drag_position + line_offset;
+ if (&draggable == insertion_handle_.get())
client_->MoveCaret(line_position);
else
client_->MoveRangeSelectionExtent(line_position);
}
-void TouchSelectionController::OnHandleDragEnd(const TouchHandle& handle) {
- if (&handle == insertion_handle_.get())
+void TouchSelectionController::OnDragEnd(
+ const TouchSelectionDraggable& draggable) {
+ if (&draggable == insertion_handle_.get())
client_->OnSelectionEvent(INSERTION_DRAG_STOPPED);
else
client_->OnSelectionEvent(SELECTION_DRAG_STOPPED);
}
+bool TouchSelectionController::IsWithinTapSlop(
+ const gfx::Vector2dF& delta) const {
+ return delta.LengthSquared() <
+ (static_cast<double>(config_.tap_slop) * config_.tap_slop);
+}
+
void TouchSelectionController::OnHandleTapped(const TouchHandle& handle) {
if (insertion_handle_ && &handle == insertion_handle_.get())
client_->OnSelectionEvent(INSERTION_TAPPED);
@@ -340,11 +370,21 @@ scoped_ptr<TouchHandleDrawable> TouchSelectionController::CreateDrawable() {
}
base::TimeDelta TouchSelectionController::GetTapTimeout() const {
- return tap_timeout_;
+ return config_.tap_timeout;
}
-float TouchSelectionController::GetTapSlop() const {
- return tap_slop_;
+void TouchSelectionController::OnLongPressDragActiveStateChanged() {
+ // The handles should remain hidden for the duration of a longpress drag,
+ // including the time between a longpress and the start of drag motion.
+ RefreshHandleVisibility();
+}
+
+gfx::PointF TouchSelectionController::GetSelectionStart() const {
+ return GetStartPosition();
+}
+
+gfx::PointF TouchSelectionController::GetSelectionEnd() const {
+ return GetEndPosition();
}
void TouchSelectionController::ShowInsertionHandleAutomatically() {
@@ -381,7 +421,7 @@ void TouchSelectionController::OnInsertionChanged() {
DeactivateSelection();
if (response_pending_input_event_ == TAP && selection_empty_ &&
- !show_on_tap_for_empty_editable_) {
+ !config_.show_on_tap_for_empty_editable) {
HideAndDisallowShowingAutomatically();
return;
}
@@ -470,6 +510,7 @@ bool TouchSelectionController::ActivateSelectionIfNecessary() {
selection_handle_dragged_ = false;
selection_start_time_ = base::TimeTicks::Now();
response_pending_input_event_ = INPUT_EVENT_TYPE_NONE;
+ longpress_drag_selector_.OnSelectionActivated();
return true;
}
return false;
@@ -481,6 +522,7 @@ void TouchSelectionController::DeactivateSelection() {
DCHECK(start_selection_handle_);
DCHECK(end_selection_handle_);
LogSelectionEnd();
+ longpress_drag_selector_.OnSelectionDeactivated();
start_selection_handle_->SetEnabled(false);
end_selection_handle_->SetEnabled(false);
active_status_ = INACTIVE;
@@ -498,6 +540,16 @@ void TouchSelectionController::ForceNextUpdateIfInactive() {
}
}
+void TouchSelectionController::RefreshHandleVisibility() {
+ TouchHandle::AnimationStyle animation_style = GetAnimationStyle(true);
+ if (active_status_ == SELECTION_ACTIVE) {
+ start_selection_handle_->SetVisible(GetStartVisible(), animation_style);
+ end_selection_handle_->SetVisible(GetEndVisible(), animation_style);
+ }
+ if (active_status_ == INSERTION_ACTIVE)
+ insertion_handle_->SetVisible(GetStartVisible(), animation_style);
+}
+
gfx::Vector2dF TouchSelectionController::GetStartLineOffset() const {
return ComputeLineOffsetFromBottom(start_);
}
@@ -507,11 +559,17 @@ gfx::Vector2dF TouchSelectionController::GetEndLineOffset() const {
}
bool TouchSelectionController::GetStartVisible() const {
- return start_.visible() && !temporarily_hidden_;
+ if (!start_.visible())
+ return false;
+
+ return !temporarily_hidden_ && !longpress_drag_selector_.IsActive();
}
bool TouchSelectionController::GetEndVisible() const {
- return end_.visible() && !temporarily_hidden_;
+ if (!end_.visible())
+ return false;
+
+ return !temporarily_hidden_ && !longpress_drag_selector_.IsActive();
}
TouchHandle::AnimationStyle TouchSelectionController::GetAnimationStyle(
« no previous file with comments | « ui/touch_selection/touch_selection_controller.h ('k') | ui/touch_selection/touch_selection_controller_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698