diff options
author | msw@chromium.org <msw@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-05-23 21:09:20 +0000 |
---|---|---|
committer | msw@chromium.org <msw@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-05-23 21:09:20 +0000 |
commit | d76fad6554e7388e10966e309333528ecb9d83b0 (patch) | |
tree | 959f91b4f843272da91dbdbfedc255425c0736c1 | |
parent | e2481a70c71654e425f0aaeea54100b49f6c0b31 (diff) | |
download | chromium_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.h | 10 | ||||
-rw-r--r-- | ui/views/controls/textfield/textfield.cc | 71 | ||||
-rw-r--r-- | ui/views/controls/textfield/textfield.h | 21 |
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_; |