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

Side by Side Diff: ui/views/selection_controller.cc

Issue 2408623002: Views: Extract text selection code from Textfield. (Closed)
Patch Set: Check for |handles_selection_clipboard_| Created 4 years, 1 month 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
« no previous file with comments | « ui/views/selection_controller.h ('k') | ui/views/selection_controller_delegate.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "ui/views/selection_controller.h"
6
7 #include <algorithm>
8
9 #include "ui/events/event.h"
10 #include "ui/gfx/render_text.h"
11 #include "ui/views/metrics.h"
12 #include "ui/views/selection_controller_delegate.h"
13 #include "ui/views/style/platform_style.h"
14 #include "ui/views/view.h"
15
16 namespace views {
17
18 SelectionController::SelectionController(SelectionControllerDelegate* delegate)
19 : aggregated_clicks_(0),
20 delegate_(delegate),
21 handles_selection_clipboard_(false) {
22 DCHECK(delegate);
23 }
24
25 bool SelectionController::OnMousePressed(const ui::MouseEvent& event,
26 bool handled) {
27 gfx::RenderText* render_text = GetRenderText();
28 DCHECK(render_text);
29
30 TrackMouseClicks(event);
31 if (handled)
32 return true;
33
34 if (event.IsOnlyLeftMouseButton()) {
35 delegate_->SetTextBeingDragged(false);
36 switch (aggregated_clicks_) {
37 case 0:
38 // If the click location is within an existing selection, it may be a
39 // potential drag and drop.
40 if (render_text->IsPointInSelection(event.location())) {
41 delegate_->SetTextBeingDragged(true);
42 } else {
43 delegate_->OnBeforePointerAction();
44 const bool selection_changed =
45 render_text->MoveCursorTo(event.location(), event.IsShiftDown());
46 delegate_->OnAfterPointerAction(false, selection_changed);
47 }
48 break;
49 case 1:
50 // Select the word at the click location on a double click.
51 delegate_->OnBeforePointerAction();
52 render_text->MoveCursorTo(event.location(), false);
53 render_text->SelectWord();
54 delegate_->OnAfterPointerAction(false, true);
55 double_click_word_ = render_text->selection();
56 break;
57 case 2:
58 // Select all the text on a triple click.
59 delegate_->OnBeforePointerAction();
60 render_text->SelectAll(false);
61 delegate_->OnAfterPointerAction(false, true);
62 break;
63 default:
64 NOTREACHED();
65 }
66 }
67
68 if (handles_selection_clipboard_ && event.IsOnlyMiddleMouseButton()) {
69 if (render_text->IsPointInSelection(event.location())) {
70 delegate_->OnBeforePointerAction();
71 render_text->ClearSelection();
72 delegate_->UpdateSelectionClipboard();
73 delegate_->OnAfterPointerAction(false, true);
74 } else if (!delegate_->IsReadOnly()) {
75 delegate_->OnBeforePointerAction();
76 const bool selection_changed =
77 render_text->MoveCursorTo(event.location(), false);
78 const bool text_changed = delegate_->PasteSelectionClipboard();
79 delegate_->OnAfterPointerAction(text_changed,
80 selection_changed | text_changed);
81 }
82 }
83
84 return true;
85 }
86
87 bool SelectionController::OnMouseDragged(const ui::MouseEvent& event) {
88 DCHECK(GetRenderText());
89 // If |drag_selection_timer_| is running, |last_drag_location_| will be used
90 // to update the selection.
91 last_drag_location_ = event.location();
92
93 // Don't adjust the cursor on a potential drag and drop.
94 if (delegate_->HasTextBeingDragged() || !event.IsOnlyLeftMouseButton())
95 return true;
96
97 // A timer is used to continuously scroll while selecting beyond side edges.
98 const int x = event.location().x();
99 const int width = delegate_->GetViewWidth();
100 const int drag_selection_delay = delegate_->GetDragSelectionDelay();
101 if ((x >= 0 && x <= width) || drag_selection_delay == 0) {
102 drag_selection_timer_.Stop();
103 SelectThroughLastDragLocation();
104 } else if (!drag_selection_timer_.IsRunning()) {
105 // Select through the edge of the visible text, then start the scroll timer.
106 last_drag_location_.set_x(std::min(std::max(0, x), width));
107 SelectThroughLastDragLocation();
108
109 drag_selection_timer_.Start(
110 FROM_HERE, base::TimeDelta::FromMilliseconds(drag_selection_delay),
111 this, &SelectionController::SelectThroughLastDragLocation);
112 }
113
114 return true;
115 }
116
117 void SelectionController::OnMouseReleased(const ui::MouseEvent& event) {
118 gfx::RenderText* render_text = GetRenderText();
119 DCHECK(render_text);
120
121 drag_selection_timer_.Stop();
122
123 // Cancel suspected drag initiations, the user was clicking in the selection.
124 if (delegate_->HasTextBeingDragged()) {
125 delegate_->OnBeforePointerAction();
126 const bool selection_changed =
127 render_text->MoveCursorTo(event.location(), false);
128 delegate_->OnAfterPointerAction(false, selection_changed);
129 }
130 delegate_->SetTextBeingDragged(false);
131
132 if (handles_selection_clipboard_ && !render_text->selection().is_empty())
karandeepb 2016/10/26 02:27:39 Also added a couple of these checks.
133 delegate_->UpdateSelectionClipboard();
134 }
135
136 void SelectionController::OnMouseCaptureLost() {
137 gfx::RenderText* render_text = GetRenderText();
138 DCHECK(render_text);
139
140 drag_selection_timer_.Stop();
141
142 if (handles_selection_clipboard_ && !render_text->selection().is_empty())
143 delegate_->UpdateSelectionClipboard();
144 }
145
146 void SelectionController::TrackMouseClicks(const ui::MouseEvent& event) {
147 if (event.IsOnlyLeftMouseButton()) {
148 base::TimeDelta time_delta = event.time_stamp() - last_click_time_;
149 if (!last_click_time_.is_null() &&
150 time_delta.InMilliseconds() <= GetDoubleClickInterval() &&
151 !View::ExceededDragThreshold(event.location() - last_click_location_)) {
152 // Upon clicking after a triple click, the count should go back to
153 // double click and alternate between double and triple. This assignment
154 // maps 0 to 1, 1 to 2, 2 to 1.
155 aggregated_clicks_ = (aggregated_clicks_ % 2) + 1;
156 } else {
157 aggregated_clicks_ = 0;
158 }
159 last_click_time_ = event.time_stamp();
160 last_click_location_ = event.location();
161 }
162 }
163
164 gfx::RenderText* SelectionController::GetRenderText() {
165 return delegate_->GetRenderTextForSelectionController();
166 }
167
168 void SelectionController::SelectThroughLastDragLocation() {
169 gfx::RenderText* render_text = GetRenderText();
170 DCHECK(render_text);
171
172 delegate_->OnBeforePointerAction();
173
174 // TODO(karandeepb): See if this can be handled at the RenderText level.
175 const bool drags_to_end = PlatformStyle::kTextfieldDragVerticallyDragsToEnd;
176 if (drags_to_end && last_drag_location_.y() < 0) {
177 render_text->MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_LEFT,
178 gfx::SELECTION_RETAIN);
179 } else if (drags_to_end &&
180 last_drag_location_.y() > delegate_->GetViewHeight()) {
181 render_text->MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_RIGHT,
182 gfx::SELECTION_RETAIN);
183 } else {
184 render_text->MoveCursorTo(last_drag_location_, true);
185 }
186
187 if (aggregated_clicks_ == 1) {
188 render_text->SelectWord();
189 // Expand the selection so the initially selected word remains selected.
190 gfx::Range selection = render_text->selection();
191 const size_t min =
192 std::min(selection.GetMin(), double_click_word_.GetMin());
193 const size_t max =
194 std::max(selection.GetMax(), double_click_word_.GetMax());
195 const bool reversed = selection.is_reversed();
196 selection.set_start(reversed ? max : min);
197 selection.set_end(reversed ? min : max);
198 render_text->SelectRange(selection);
199 }
200 delegate_->OnAfterPointerAction(false, true);
201 }
202
203 } // namespace views
OLDNEW
« no previous file with comments | « ui/views/selection_controller.h ('k') | ui/views/selection_controller_delegate.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698