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

Side by Side Diff: ui/touch_selection/touch_handle.cc

Issue 481683003: Support for Adaptive Handle Orientation (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: unittests Created 5 years, 6 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_handle.h" 5 #include "ui/touch_selection/touch_handle.h"
6 6
7 #include <cmath> 7 #include <cmath>
8 8
9 namespace ui { 9 namespace ui {
10 10
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
56 return os << "CENTER"; 56 return os << "CENTER";
57 case TouchHandleOrientation::UNDEFINED: 57 case TouchHandleOrientation::UNDEFINED:
58 return os << "UNDEFINED"; 58 return os << "UNDEFINED";
59 default: 59 default:
60 return os << "INVALID: " << static_cast<int>(orientation); 60 return os << "INVALID: " << static_cast<int>(orientation);
61 } 61 }
62 } 62 }
63 63
64 // Responsible for rendering a selection or insertion handle for text editing. 64 // Responsible for rendering a selection or insertion handle for text editing.
65 TouchHandle::TouchHandle(TouchHandleClient* client, 65 TouchHandle::TouchHandle(TouchHandleClient* client,
66 TouchHandleOrientation orientation) 66 TouchHandleOrientation orientation,
67 const gfx::RectF viewport_rect)
67 : drawable_(client->CreateDrawable()), 68 : drawable_(client->CreateDrawable()),
68 client_(client), 69 client_(client),
70 viewport_rect_(viewport_rect),
69 orientation_(orientation), 71 orientation_(orientation),
70 deferred_orientation_(TouchHandleOrientation::UNDEFINED), 72 deferred_orientation_(TouchHandleOrientation::UNDEFINED),
71 alpha_(0.f), 73 alpha_(0.f),
72 animate_deferred_fade_(false), 74 animate_deferred_fade_(false),
73 enabled_(true), 75 enabled_(true),
74 is_visible_(false), 76 is_visible_(false),
75 is_dragging_(false), 77 is_dragging_(false),
76 is_drag_within_tap_region_(false) { 78 is_drag_within_tap_region_(false),
79 mirror_vertical_(false),
80 mirror_horizontal_(false) {
77 DCHECK_NE(orientation, TouchHandleOrientation::UNDEFINED); 81 DCHECK_NE(orientation, TouchHandleOrientation::UNDEFINED);
78 drawable_->SetEnabled(enabled_); 82 drawable_->SetEnabled(enabled_);
79 drawable_->SetOrientation(orientation_); 83 drawable_->SetLayout(focus_bottom_, orientation_, false, false);
80 drawable_->SetAlpha(alpha_); 84 drawable_->SetAlpha(alpha_);
81 drawable_->SetFocus(position_); 85 handle_padding_ = drawable_->GetDrawablePadding();
82 } 86 }
83 87
84 TouchHandle::~TouchHandle() { 88 TouchHandle::~TouchHandle() {
85 } 89 }
86 90
87 void TouchHandle::SetEnabled(bool enabled) { 91 void TouchHandle::SetEnabled(bool enabled) {
88 if (enabled_ == enabled) 92 if (enabled_ == enabled)
89 return; 93 return;
90 if (!enabled) { 94 if (!enabled) {
91 EndDrag(); 95 EndDrag();
92 EndFade(); 96 EndFade();
93 } 97 }
94 enabled_ = enabled; 98 enabled_ = enabled;
95 drawable_->SetEnabled(enabled); 99 drawable_->SetEnabled(enabled);
96 } 100 }
97 101
98 void TouchHandle::SetVisible(bool visible, AnimationStyle animation_style) { 102 void TouchHandle::SetVisible(bool visible, AnimationStyle animation_style) {
99 DCHECK(enabled_); 103 DCHECK(enabled_);
100 if (is_visible_ == visible) 104 if (is_visible_ == visible)
101 return; 105 return;
102 106
103 is_visible_ = visible; 107 is_visible_ = visible;
104 108
105 // Handle repositioning may have been deferred while previously invisible. 109 // Handle repositioning may have been deferred while previously invisible.
106 if (visible) 110 UpdateLayout();
107 drawable_->SetFocus(position_);
108 111
109 bool animate = animation_style != ANIMATION_NONE; 112 bool animate = animation_style != ANIMATION_NONE;
110 if (is_dragging_) { 113 if (is_dragging_) {
111 animate_deferred_fade_ = animate; 114 animate_deferred_fade_ = animate;
112 return; 115 return;
113 } 116 }
114 117
115 if (animate) 118 if (animate)
116 BeginFade(); 119 BeginFade();
117 else 120 else
118 EndFade(); 121 EndFade();
119 } 122 }
120 123
121 void TouchHandle::SetPosition(const gfx::PointF& position) { 124 void TouchHandle::SetFocus(const gfx::PointF& top, const gfx::PointF& bottom) {
122 DCHECK(enabled_); 125 if (focus_top_ == top && focus_bottom_ == bottom)
123 if (position_ == position)
124 return; 126 return;
125 position_ = position; 127
126 // Suppress repositioning a handle while invisible or fading out to prevent it 128 focus_top_ = top;
127 // from "ghosting" outside the visible bounds. The position will be pushed to 129 focus_bottom_ = bottom;
128 // the drawable when the handle regains visibility (see |SetVisible()|). 130 UpdateLayout();
129 if (is_visible_) 131 }
130 drawable_->SetFocus(position_); 132
133 void TouchHandle::SetViewportRect(const gfx::RectF viewport_rect) {
134 if (viewport_rect_ == viewport_rect)
135 return;
136
137 viewport_rect_ = viewport_rect;
138 UpdateLayout();
131 } 139 }
132 140
133 void TouchHandle::SetOrientation(TouchHandleOrientation orientation) { 141 void TouchHandle::SetOrientation(TouchHandleOrientation orientation) {
134 DCHECK(enabled_); 142 DCHECK(enabled_);
135 DCHECK_NE(orientation, TouchHandleOrientation::UNDEFINED); 143 DCHECK_NE(orientation, TouchHandleOrientation::UNDEFINED);
136 if (is_dragging_) { 144 if (is_dragging_) {
137 deferred_orientation_ = orientation; 145 deferred_orientation_ = orientation;
138 return; 146 return;
139 } 147 }
140 DCHECK_EQ(deferred_orientation_, TouchHandleOrientation::UNDEFINED); 148 DCHECK_EQ(deferred_orientation_, TouchHandleOrientation::UNDEFINED);
141 if (orientation_ == orientation) 149 if (orientation_ == orientation)
142 return; 150 return;
143 151
144 orientation_ = orientation; 152 orientation_ = orientation;
145 drawable_->SetOrientation(orientation); 153 UpdateLayout();
146 } 154 }
147 155
148 bool TouchHandle::WillHandleTouchEvent(const MotionEvent& event) { 156 bool TouchHandle::WillHandleTouchEvent(const MotionEvent& event) {
149 if (!enabled_) 157 if (!enabled_)
150 return false; 158 return false;
151 159
152 if (!is_dragging_ && event.GetAction() != MotionEvent::ACTION_DOWN) 160 if (!is_dragging_ && event.GetAction() != MotionEvent::ACTION_DOWN)
153 return false; 161 return false;
154 162
155 switch (event.GetAction()) { 163 switch (event.GetAction()) {
156 case MotionEvent::ACTION_DOWN: { 164 case MotionEvent::ACTION_DOWN: {
157 if (!is_visible_) 165 if (!is_visible_)
158 return false; 166 return false;
159 const gfx::PointF touch_point(event.GetX(), event.GetY()); 167 const gfx::PointF touch_point(event.GetX(), event.GetY());
160 const float touch_radius = std::max( 168 const float touch_radius = std::max(
161 kMinTouchMajorForHitTesting, 169 kMinTouchMajorForHitTesting,
162 std::min(kMaxTouchMajorForHitTesting, event.GetTouchMajor())) * 0.5f; 170 std::min(kMaxTouchMajorForHitTesting, event.GetTouchMajor())) * 0.5f;
163 if (!RectIntersectsCircle(drawable_->GetVisibleBounds(), 171 if (!RectIntersectsCircle(drawable_->GetVisibleBounds(),
164 touch_point, 172 touch_point,
165 touch_radius)) { 173 touch_radius)) {
166 EndDrag(); 174 EndDrag();
167 return false; 175 return false;
168 } 176 }
169 touch_down_position_ = touch_point; 177 touch_down_position_ = touch_point;
170 touch_to_focus_offset_ = position_ - touch_down_position_; 178 touch_to_focus_offset_ = focus_bottom_ - touch_down_position_;
171 touch_down_time_ = event.GetEventTime(); 179 touch_down_time_ = event.GetEventTime();
172 BeginDrag(); 180 BeginDrag();
173 } break; 181 } break;
174 182
175 case MotionEvent::ACTION_MOVE: { 183 case MotionEvent::ACTION_MOVE: {
176 gfx::PointF touch_move_position(event.GetX(), event.GetY()); 184 gfx::PointF touch_move_position(event.GetX(), event.GetY());
177 if (is_drag_within_tap_region_) { 185 if (is_drag_within_tap_region_) {
178 const float tap_slop = client_->GetTapSlop(); 186 const float tap_slop = client_->GetTapSlop();
179 is_drag_within_tap_region_ = 187 is_drag_within_tap_region_ =
180 (touch_move_position - touch_down_position_).LengthSquared() < 188 (touch_move_position - touch_down_position_).LengthSquared() <
(...skipping 27 matching lines...) Expand all
208 } 216 }
209 217
210 bool TouchHandle::Animate(base::TimeTicks frame_time) { 218 bool TouchHandle::Animate(base::TimeTicks frame_time) {
211 if (fade_end_time_ == base::TimeTicks()) 219 if (fade_end_time_ == base::TimeTicks())
212 return false; 220 return false;
213 221
214 DCHECK(enabled_); 222 DCHECK(enabled_);
215 223
216 float time_u = 224 float time_u =
217 1.f - (fade_end_time_ - frame_time).InMillisecondsF() / kFadeDurationMs; 225 1.f - (fade_end_time_ - frame_time).InMillisecondsF() / kFadeDurationMs;
218 float position_u = 226 float position_u = (focus_bottom_ - fade_start_position_).LengthSquared() /
219 (position_ - fade_start_position_).LengthSquared() / kFadeDistanceSquared; 227 kFadeDistanceSquared;
220 float u = std::max(time_u, position_u); 228 float u = std::max(time_u, position_u);
221 SetAlpha(is_visible_ ? u : 1.f - u); 229 SetAlpha(is_visible_ ? u : 1.f - u);
222 230
223 if (u >= 1.f) { 231 if (u >= 1.f) {
224 EndFade(); 232 EndFade();
225 return false; 233 return false;
226 } 234 }
227 235
228 return true; 236 return true;
229 } 237 }
230 238
231 gfx::RectF TouchHandle::GetVisibleBounds() const { 239 gfx::RectF TouchHandle::GetVisibleBounds() const {
232 if (!is_visible_ || !enabled_) 240 if (!is_visible_ || !enabled_)
233 return gfx::RectF(); 241 return gfx::RectF();
234 242
235 return drawable_->GetVisibleBounds(); 243 return drawable_->GetVisibleBounds();
236 } 244 }
237 245
246 void TouchHandle::UpdateLayout() {
247 // Suppress repositioning a handle while invisible or fading out to prevent it
248 // from "ghosting" outside the visible bounds. The position will be pushed to
249 // the drawable when the handle regains visibility (see |SetVisible()|).
250 if (!is_visible_)
251 return;
252
253 // Update mirror values only when dragging has stopped to prevent unwanted
254 // inversion while dragging of handles
255 if (!is_dragging_) {
256 gfx::RectF handle_bounds = drawable_->GetVisibleBounds();
257 bool mirror_horizontal = false;
258 bool mirror_vertical = false;
259
260 const float handle_width =
261 handle_bounds.width() * (1.0 - handle_padding_.width());
262 const float handle_height =
263 handle_bounds.height() * (1.0 - handle_padding_.height());
264
265 const float bottom_y_unmirrored =
266 focus_bottom_.y() + handle_height + viewport_rect_.y();
267 const float top_y_mirrored =
268 focus_top_.y() - handle_height + viewport_rect_.y();
269
270 // In case the viewport height is small, like webview, avoid inversion.
271 if (bottom_y_unmirrored > viewport_rect_.bottom() &&
272 top_y_mirrored > viewport_rect_.y()) {
273 mirror_vertical = true;
274 }
275
276 if (orientation_ == TouchHandleOrientation::LEFT &&
277 focus_bottom_.x() - handle_width < viewport_rect_.x()) {
278 mirror_horizontal = true;
279 } else if (orientation_ == TouchHandleOrientation::RIGHT &&
280 focus_bottom_.x() + handle_width > viewport_rect_.right()) {
281 mirror_horizontal = true;
282 }
283
284 mirror_horizontal_ = mirror_horizontal;
285 mirror_vertical_ = mirror_vertical;
286 }
287
288 gfx::PointF position = mirror_vertical_ ? focus_top_ : focus_bottom_;
289
290 drawable_->SetLayout(position, orientation_, mirror_vertical_,
291 mirror_horizontal_);
292 }
293
238 void TouchHandle::BeginDrag() { 294 void TouchHandle::BeginDrag() {
239 DCHECK(enabled_); 295 DCHECK(enabled_);
240 if (is_dragging_) 296 if (is_dragging_)
241 return; 297 return;
242 EndFade(); 298 EndFade();
243 is_dragging_ = true; 299 is_dragging_ = true;
244 is_drag_within_tap_region_ = true; 300 is_drag_within_tap_region_ = true;
245 client_->OnHandleDragBegin(*this); 301 client_->OnHandleDragBegin(*this);
246 } 302 }
247 303
248 void TouchHandle::EndDrag() { 304 void TouchHandle::EndDrag() {
249 DCHECK(enabled_); 305 DCHECK(enabled_);
250 if (!is_dragging_) 306 if (!is_dragging_)
251 return; 307 return;
252 308
253 is_dragging_ = false; 309 is_dragging_ = false;
254 is_drag_within_tap_region_ = false; 310 is_drag_within_tap_region_ = false;
255 client_->OnHandleDragEnd(*this); 311 client_->OnHandleDragEnd(*this);
256 312
257 if (deferred_orientation_ != TouchHandleOrientation::UNDEFINED) { 313 if (deferred_orientation_ != TouchHandleOrientation::UNDEFINED) {
258 TouchHandleOrientation deferred_orientation = deferred_orientation_; 314 TouchHandleOrientation deferred_orientation = deferred_orientation_;
259 deferred_orientation_ = TouchHandleOrientation::UNDEFINED; 315 deferred_orientation_ = TouchHandleOrientation::UNDEFINED;
260 SetOrientation(deferred_orientation); 316 SetOrientation(deferred_orientation);
317 // Handle layout may is deferred while the handle is dragged.
318 UpdateLayout();
261 } 319 }
262 320
263 if (animate_deferred_fade_) { 321 if (animate_deferred_fade_) {
264 BeginFade(); 322 BeginFade();
265 } else { 323 } else {
266 // As drawable visibility assignment is deferred while dragging, push the 324 // As drawable visibility assignment is deferred while dragging, push the
267 // change by forcing fade completion. 325 // change by forcing fade completion.
268 EndFade(); 326 EndFade();
269 } 327 }
270 } 328 }
271 329
272 void TouchHandle::BeginFade() { 330 void TouchHandle::BeginFade() {
273 DCHECK(enabled_); 331 DCHECK(enabled_);
274 DCHECK(!is_dragging_); 332 DCHECK(!is_dragging_);
275 animate_deferred_fade_ = false; 333 animate_deferred_fade_ = false;
276 const float target_alpha = is_visible_ ? 1.f : 0.f; 334 const float target_alpha = is_visible_ ? 1.f : 0.f;
277 if (target_alpha == alpha_) { 335 if (target_alpha == alpha_) {
278 EndFade(); 336 EndFade();
279 return; 337 return;
280 } 338 }
281 339
282 fade_end_time_ = base::TimeTicks::Now() + 340 fade_end_time_ = base::TimeTicks::Now() +
283 base::TimeDelta::FromMillisecondsD( 341 base::TimeDelta::FromMillisecondsD(
284 kFadeDurationMs * std::abs(target_alpha - alpha_)); 342 kFadeDurationMs * std::abs(target_alpha - alpha_));
285 fade_start_position_ = position_; 343 fade_start_position_ = focus_bottom_;
286 client_->SetNeedsAnimate(); 344 client_->SetNeedsAnimate();
287 } 345 }
288 346
289 void TouchHandle::EndFade() { 347 void TouchHandle::EndFade() {
290 DCHECK(enabled_); 348 DCHECK(enabled_);
291 animate_deferred_fade_ = false; 349 animate_deferred_fade_ = false;
292 fade_end_time_ = base::TimeTicks(); 350 fade_end_time_ = base::TimeTicks();
293 SetAlpha(is_visible_ ? 1.f : 0.f); 351 SetAlpha(is_visible_ ? 1.f : 0.f);
294 } 352 }
295 353
296 void TouchHandle::SetAlpha(float alpha) { 354 void TouchHandle::SetAlpha(float alpha) {
297 alpha = std::max(0.f, std::min(1.f, alpha)); 355 alpha = std::max(0.f, std::min(1.f, alpha));
298 if (alpha_ == alpha) 356 if (alpha_ == alpha)
299 return; 357 return;
300 alpha_ = alpha; 358 alpha_ = alpha;
301 drawable_->SetAlpha(alpha); 359 drawable_->SetAlpha(alpha);
302 } 360 }
303 361
304 } // namespace ui 362 } // namespace ui
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698