summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authormsw@chromium.org <msw@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-05-23 21:09:20 +0000
committermsw@chromium.org <msw@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-05-23 21:09:20 +0000
commitd76fad6554e7388e10966e309333528ecb9d83b0 (patch)
tree959f91b4f843272da91dbdbfedc255425c0736c1
parente2481a70c71654e425f0aaeea54100b49f6c0b31 (diff)
downloadchromium_src-d76fad6554e7388e10966e309333528ecb9d83b0.zip
chromium_src-d76fad6554e7388e10966e309333528ecb9d83b0.tar.gz
chromium_src-d76fad6554e7388e10966e309333528ecb9d83b0.tar.bz2
Make Textfield scroll continuously when dragging beyond edges.
Add a timer, point, and function drag selection helpers. Respect ScopedAnimationDurationScaleMode for TextfieldTest.DragToSelect. Comment and function order cleanup; fix timer.h indentation. TODO(followup): Make the scrolling "animation" smoother. BUG=373886 TEST=Dragging to select beyond the left or right ends of the omnibox, find bar textfield, etc. continuously scrolls and modifies the selection. R=pkasting@chromium.org,thakis@chromium.org,sky@chromium.org Review URL: https://codereview.chromium.org/290733007 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@272591 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--base/timer/timer.h10
-rw-r--r--ui/views/controls/textfield/textfield.cc71
-rw-r--r--ui/views/controls/textfield/textfield.h21
3 files changed, 66 insertions, 36 deletions
diff --git a/base/timer/timer.h b/base/timer/timer.h
index eb943eb..6d282ee 100644
--- a/base/timer/timer.h
+++ b/base/timer/timer.h
@@ -90,8 +90,8 @@ class BASE_EXPORT Timer {
// Start the timer to run at the given |delay| from now. If the timer is
// already running, it will be replaced to call the given |user_task|.
virtual void Start(const tracked_objects::Location& posted_from,
- TimeDelta delay,
- const base::Closure& user_task);
+ TimeDelta delay,
+ const base::Closure& user_task);
// Call this method to stop and cancel the timer. It is a no-op if the timer
// is not running.
@@ -197,9 +197,9 @@ class BaseTimerMethodPointer : public Timer {
// already running, it will be replaced to call a task formed from
// |reviewer->*method|.
virtual void Start(const tracked_objects::Location& posted_from,
- TimeDelta delay,
- Receiver* receiver,
- ReceiverMethod method) {
+ TimeDelta delay,
+ Receiver* receiver,
+ ReceiverMethod method) {
Timer::Start(posted_from, delay,
base::Bind(method, base::Unretained(receiver)));
}
diff --git a/ui/views/controls/textfield/textfield.cc b/ui/views/controls/textfield/textfield.cc
index 68aa01e..0202b0f 100644
--- a/ui/views/controls/textfield/textfield.cc
+++ b/ui/views/controls/textfield/textfield.cc
@@ -15,6 +15,7 @@
#include "ui/base/dragdrop/drag_utils.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/base/ui_base_switches_util.h"
+#include "ui/compositor/scoped_animation_duration_scale_mode.h"
#include "ui/events/event.h"
#include "ui/events/keycodes/keyboard_codes.h"
#include "ui/gfx/canvas.h"
@@ -63,6 +64,17 @@ void ConvertRectToScreen(const View* src, gfx::Rect* r) {
r->set_origin(new_origin);
}
+// Get the drag selection timer delay, respecting animation scaling for testing.
+int GetDragSelectionDelay() {
+ switch (ui::ScopedAnimationDurationScaleMode::duration_scale_mode()) {
+ case ui::ScopedAnimationDurationScaleMode::NORMAL_DURATION: return 100;
+ case ui::ScopedAnimationDurationScaleMode::FAST_DURATION: return 25;
+ case ui::ScopedAnimationDurationScaleMode::SLOW_DURATION: return 400;
+ case ui::ScopedAnimationDurationScaleMode::ZERO_DURATION: return 0;
+ }
+ return 100;
+}
+
int GetCommandForKeyEvent(const ui::KeyEvent& event, bool has_selection) {
if (event.type() != ui::ET_KEY_PRESSED || event.IsUnicodeKeyCode())
return kNoCommand;
@@ -312,16 +324,16 @@ base::i18n::TextDirection Textfield::GetTextDirection() const {
return GetRenderText()->GetTextDirection();
}
+base::string16 Textfield::GetSelectedText() const {
+ return model_->GetSelectedText();
+}
+
void Textfield::SelectAll(bool reversed) {
model_->SelectAll(reversed);
UpdateSelectionClipboard();
UpdateAfterChange(false, true);
}
-base::string16 Textfield::GetSelectedText() const {
- return model_->GetSelectedText();
-}
-
void Textfield::ClearSelection() {
model_->ClearSelection();
UpdateAfterChange(false, true);
@@ -552,35 +564,32 @@ bool Textfield::OnMousePressed(const ui::MouseEvent& event) {
}
bool Textfield::OnMouseDragged(const ui::MouseEvent& event) {
+ last_drag_location_ = event.location();
+
// Don't adjust the cursor on a potential drag and drop, or if the mouse
// movement from the last mouse click does not exceed the drag threshold.
if (initiating_drag_ || !event.IsOnlyLeftMouseButton() ||
- !ExceededDragThreshold(event.location() - last_click_location_)) {
+ !ExceededDragThreshold(last_drag_location_ - last_click_location_)) {
return true;
}
- OnBeforeUserAction();
- model_->MoveCursorTo(event.location(), true);
- if (aggregated_clicks_ == 1) {
- model_->SelectWord();
- // Expand the selection so the initially selected word remains selected.
- gfx::Range selection = GetRenderText()->selection();
- const size_t min = std::min(selection.GetMin(),
- double_click_word_.GetMin());
- const size_t max = std::max(selection.GetMax(),
- double_click_word_.GetMax());
- const bool reversed = selection.is_reversed();
- selection.set_start(reversed ? max : min);
- selection.set_end(reversed ? min : max);
- model_->SelectRange(selection);
+ // A timer is used to continuously scroll while selecting beyond side edges.
+ if ((event.location().x() > 0 && event.location().x() < size().width()) ||
+ GetDragSelectionDelay() == 0) {
+ drag_selection_timer_.Stop();
+ SelectThroughLastDragLocation();
+ } else if (!drag_selection_timer_.IsRunning()) {
+ drag_selection_timer_.Start(
+ FROM_HERE, base::TimeDelta::FromMilliseconds(GetDragSelectionDelay()),
+ this, &Textfield::SelectThroughLastDragLocation);
}
- UpdateAfterChange(false, true);
- OnAfterUserAction();
+
return true;
}
void Textfield::OnMouseReleased(const ui::MouseEvent& event) {
OnBeforeUserAction();
+ drag_selection_timer_.Stop();
// Cancel suspected drag initiations, the user was clicking in the selection.
if (initiating_drag_)
MoveCursorTo(event.location(), false);
@@ -1542,6 +1551,26 @@ void Textfield::MoveCursorTo(const gfx::Point& point, bool select) {
UpdateAfterChange(false, true);
}
+void Textfield::SelectThroughLastDragLocation() {
+ OnBeforeUserAction();
+ model_->MoveCursorTo(last_drag_location_, true);
+ if (aggregated_clicks_ == 1) {
+ model_->SelectWord();
+ // Expand the selection so the initially selected word remains selected.
+ gfx::Range selection = GetRenderText()->selection();
+ const size_t min = std::min(selection.GetMin(),
+ double_click_word_.GetMin());
+ const size_t max = std::max(selection.GetMax(),
+ double_click_word_.GetMax());
+ const bool reversed = selection.is_reversed();
+ selection.set_start(reversed ? max : min);
+ selection.set_end(reversed ? min : max);
+ model_->SelectRange(selection);
+ }
+ UpdateAfterChange(false, true);
+ OnAfterUserAction();
+}
+
void Textfield::OnCaretBoundsChanged() {
if (GetInputMethod())
GetInputMethod()->OnCaretBoundsChanged(this);
diff --git a/ui/views/controls/textfield/textfield.h b/ui/views/controls/textfield/textfield.h
index 61ef634..8c81c6f 100644
--- a/ui/views/controls/textfield/textfield.h
+++ b/ui/views/controls/textfield/textfield.h
@@ -317,6 +317,9 @@ class VIEWS_EXPORT Textfield : public View,
// Helper function to call MoveCursorTo on the TextfieldModel.
void MoveCursorTo(const gfx::Point& point, bool select);
+ // Helper function to update the selection on a mouse drag.
+ void SelectThroughLastDragLocation();
+
// Convenience method to notify the InputMethod and TouchSelectionController.
void OnCaretBoundsChanged();
@@ -372,16 +375,11 @@ class VIEWS_EXPORT Textfield : public View,
scoped_ptr<Painter> focus_painter_;
- // Text color. Only used if |use_default_text_color_| is false.
+ // Flags indicating whether text and background system colors should be used,
+ // and the actual color values used if the corresponding flags are set false.
SkColor text_color_;
-
- // Should we use the system text color instead of |text_color_|?
bool use_default_text_color_;
-
- // Background color. Only used if |use_default_background_color_| is false.
SkColor background_color_;
-
- // Should we use the system background color instead of |background_color_|?
bool use_default_background_color_;
// Text to display when empty.
@@ -400,9 +398,8 @@ class VIEWS_EXPORT Textfield : public View,
base::TimeDelta password_reveal_duration_;
base::OneShotTimer<Textfield> password_reveal_timer_;
- // Keeps track of whether currently performing a user action (i.e. when
- // OnBeforeUserAction() has been called, but OnAfterUserAction() is yet to be
- // called).
+ // Tracks whether a user action is being performed; i.e. OnBeforeUserAction()
+ // has been called, but OnAfterUserAction() has not yet been called.
bool performing_user_action_;
// True if InputMethod::CancelComposition() should not be called.
@@ -419,6 +416,10 @@ class VIEWS_EXPORT Textfield : public View,
// Is the user potentially dragging and dropping from this view?
bool initiating_drag_;
+ // A timer and point used to modify the selection when dragging.
+ base::RepeatingTimer<Textfield> drag_selection_timer_;
+ gfx::Point last_drag_location_;
+
// State variables used to track double and triple clicks.
size_t aggregated_clicks_;
base::TimeDelta last_click_time_;