OLD | NEW |
---|---|
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 Loading... | |
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 is_handle_layout_update_required_(false), | |
80 mirror_vertical_(false), | |
81 mirror_horizontal_(false) { | |
77 DCHECK_NE(orientation, TouchHandleOrientation::UNDEFINED); | 82 DCHECK_NE(orientation, TouchHandleOrientation::UNDEFINED); |
78 drawable_->SetEnabled(enabled_); | 83 drawable_->SetEnabled(enabled_); |
79 drawable_->SetOrientation(orientation_); | 84 drawable_->SetOrientation(orientation_, false, false); |
85 drawable_->SetOrigin(focus_bottom_); | |
80 drawable_->SetAlpha(alpha_); | 86 drawable_->SetAlpha(alpha_); |
81 drawable_->SetFocus(position_); | 87 handle_horizontal_padding_ = drawable_->GetDrawableHorizontalPadding(); |
82 } | 88 } |
83 | 89 |
84 TouchHandle::~TouchHandle() { | 90 TouchHandle::~TouchHandle() { |
85 } | 91 } |
86 | 92 |
87 void TouchHandle::SetEnabled(bool enabled) { | 93 void TouchHandle::SetEnabled(bool enabled) { |
88 if (enabled_ == enabled) | 94 if (enabled_ == enabled) |
89 return; | 95 return; |
90 if (!enabled) { | 96 if (!enabled) { |
91 EndDrag(); | 97 EndDrag(); |
92 EndFade(); | 98 EndFade(); |
93 } | 99 } |
94 enabled_ = enabled; | 100 enabled_ = enabled; |
95 drawable_->SetEnabled(enabled); | 101 drawable_->SetEnabled(enabled); |
96 } | 102 } |
97 | 103 |
98 void TouchHandle::SetVisible(bool visible, AnimationStyle animation_style) { | 104 void TouchHandle::SetVisible(bool visible, AnimationStyle animation_style) { |
99 DCHECK(enabled_); | 105 DCHECK(enabled_); |
100 if (is_visible_ == visible) | 106 if (is_visible_ == visible) |
101 return; | 107 return; |
102 | 108 |
103 is_visible_ = visible; | 109 is_visible_ = visible; |
104 | 110 |
105 // Handle repositioning may have been deferred while previously invisible. | 111 // Handle repositioning may have been deferred while previously invisible. |
106 if (visible) | 112 SetUpdateLayoutRequired(); |
mfomitchev
2015/08/06 14:33:02
if (visible) ?
AviD
2015/08/09 13:55:41
There is a visibility check in SetUpdateLayoutRequ
mfomitchev
2015/08/10 13:23:45
Yeah, I realize we check visibility in UpdateHandl
AviD
2015/08/10 14:16:10
Added the visibility check here.
| |
107 drawable_->SetFocus(position_); | |
108 | 113 |
109 bool animate = animation_style != ANIMATION_NONE; | 114 bool animate = animation_style != ANIMATION_NONE; |
110 if (is_dragging_) { | 115 if (is_dragging_) { |
111 animate_deferred_fade_ = animate; | 116 animate_deferred_fade_ = animate; |
112 return; | 117 return; |
113 } | 118 } |
114 | 119 |
115 if (animate) | 120 if (animate) |
116 BeginFade(); | 121 BeginFade(); |
117 else | 122 else |
118 EndFade(); | 123 EndFade(); |
119 } | 124 } |
120 | 125 |
121 void TouchHandle::SetPosition(const gfx::PointF& position) { | 126 void TouchHandle::SetFocus(const gfx::PointF& top, const gfx::PointF& bottom) { |
122 DCHECK(enabled_); | 127 if (focus_top_ == top && focus_bottom_ == bottom) |
123 if (position_ == position) | |
124 return; | 128 return; |
125 position_ = position; | 129 |
126 // Suppress repositioning a handle while invisible or fading out to prevent it | 130 focus_top_ = top; |
127 // from "ghosting" outside the visible bounds. The position will be pushed to | 131 focus_bottom_ = bottom; |
128 // the drawable when the handle regains visibility (see |SetVisible()|). | 132 SetUpdateLayoutRequired(); |
129 if (is_visible_) | 133 } |
130 drawable_->SetFocus(position_); | 134 |
135 void TouchHandle::SetViewportRect(const gfx::RectF viewport_rect) { | |
136 if (viewport_rect_ == viewport_rect) | |
137 return; | |
138 | |
139 viewport_rect_ = viewport_rect; | |
140 SetUpdateLayoutRequired(); | |
131 } | 141 } |
132 | 142 |
133 void TouchHandle::SetOrientation(TouchHandleOrientation orientation) { | 143 void TouchHandle::SetOrientation(TouchHandleOrientation orientation) { |
134 DCHECK(enabled_); | 144 DCHECK(enabled_); |
135 DCHECK_NE(orientation, TouchHandleOrientation::UNDEFINED); | 145 DCHECK_NE(orientation, TouchHandleOrientation::UNDEFINED); |
136 if (is_dragging_) { | 146 if (is_dragging_) { |
137 deferred_orientation_ = orientation; | 147 deferred_orientation_ = orientation; |
138 return; | 148 return; |
139 } | 149 } |
140 DCHECK_EQ(deferred_orientation_, TouchHandleOrientation::UNDEFINED); | 150 DCHECK_EQ(deferred_orientation_, TouchHandleOrientation::UNDEFINED); |
141 if (orientation_ == orientation) | 151 if (orientation_ == orientation) |
142 return; | 152 return; |
143 | 153 |
144 orientation_ = orientation; | 154 orientation_ = orientation; |
145 drawable_->SetOrientation(orientation); | 155 SetUpdateLayoutRequired(); |
146 } | 156 } |
147 | 157 |
148 bool TouchHandle::WillHandleTouchEvent(const MotionEvent& event) { | 158 bool TouchHandle::WillHandleTouchEvent(const MotionEvent& event) { |
149 if (!enabled_) | 159 if (!enabled_) |
150 return false; | 160 return false; |
151 | 161 |
152 if (!is_dragging_ && event.GetAction() != MotionEvent::ACTION_DOWN) | 162 if (!is_dragging_ && event.GetAction() != MotionEvent::ACTION_DOWN) |
153 return false; | 163 return false; |
154 | 164 |
155 switch (event.GetAction()) { | 165 switch (event.GetAction()) { |
156 case MotionEvent::ACTION_DOWN: { | 166 case MotionEvent::ACTION_DOWN: { |
157 if (!is_visible_) | 167 if (!is_visible_) |
158 return false; | 168 return false; |
159 const gfx::PointF touch_point(event.GetX(), event.GetY()); | 169 const gfx::PointF touch_point(event.GetX(), event.GetY()); |
160 const float touch_radius = std::max( | 170 const float touch_radius = std::max( |
161 kMinTouchMajorForHitTesting, | 171 kMinTouchMajorForHitTesting, |
162 std::min(kMaxTouchMajorForHitTesting, event.GetTouchMajor())) * 0.5f; | 172 std::min(kMaxTouchMajorForHitTesting, event.GetTouchMajor())) * 0.5f; |
163 if (!RectIntersectsCircle(drawable_->GetVisibleBounds(), | 173 if (!RectIntersectsCircle(drawable_->GetVisibleBounds(), |
164 touch_point, | 174 touch_point, |
165 touch_radius)) { | 175 touch_radius)) { |
166 EndDrag(); | 176 EndDrag(); |
167 return false; | 177 return false; |
168 } | 178 } |
169 touch_down_position_ = touch_point; | 179 touch_down_position_ = touch_point; |
170 touch_drag_offset_ = position_ - touch_down_position_; | 180 touch_drag_offset_ = focus_bottom_ - touch_down_position_; |
171 touch_down_time_ = event.GetEventTime(); | 181 touch_down_time_ = event.GetEventTime(); |
172 BeginDrag(); | 182 BeginDrag(); |
173 } break; | 183 } break; |
174 | 184 |
175 case MotionEvent::ACTION_MOVE: { | 185 case MotionEvent::ACTION_MOVE: { |
176 gfx::PointF touch_move_position(event.GetX(), event.GetY()); | 186 gfx::PointF touch_move_position(event.GetX(), event.GetY()); |
177 is_drag_within_tap_region_ &= | 187 is_drag_within_tap_region_ &= |
178 client_->IsWithinTapSlop(touch_down_position_ - touch_move_position); | 188 client_->IsWithinTapSlop(touch_down_position_ - touch_move_position); |
179 | 189 |
180 // Note that we signal drag update even if we're inside the tap region, | 190 // Note that we signal drag update even if we're inside the tap region, |
(...skipping 26 matching lines...) Expand all Loading... | |
207 } | 217 } |
208 | 218 |
209 bool TouchHandle::Animate(base::TimeTicks frame_time) { | 219 bool TouchHandle::Animate(base::TimeTicks frame_time) { |
210 if (fade_end_time_ == base::TimeTicks()) | 220 if (fade_end_time_ == base::TimeTicks()) |
211 return false; | 221 return false; |
212 | 222 |
213 DCHECK(enabled_); | 223 DCHECK(enabled_); |
214 | 224 |
215 float time_u = | 225 float time_u = |
216 1.f - (fade_end_time_ - frame_time).InMillisecondsF() / kFadeDurationMs; | 226 1.f - (fade_end_time_ - frame_time).InMillisecondsF() / kFadeDurationMs; |
217 float position_u = | 227 float position_u = (focus_bottom_ - fade_start_position_).LengthSquared() / |
218 (position_ - fade_start_position_).LengthSquared() / kFadeDistanceSquared; | 228 kFadeDistanceSquared; |
219 float u = std::max(time_u, position_u); | 229 float u = std::max(time_u, position_u); |
220 SetAlpha(is_visible_ ? u : 1.f - u); | 230 SetAlpha(is_visible_ ? u : 1.f - u); |
221 | 231 |
222 if (u >= 1.f) { | 232 if (u >= 1.f) { |
223 EndFade(); | 233 EndFade(); |
224 return false; | 234 return false; |
225 } | 235 } |
226 | 236 |
227 return true; | 237 return true; |
228 } | 238 } |
229 | 239 |
230 gfx::RectF TouchHandle::GetVisibleBounds() const { | 240 gfx::RectF TouchHandle::GetVisibleBounds() const { |
231 if (!is_visible_ || !enabled_) | 241 if (!is_visible_ || !enabled_) |
232 return gfx::RectF(); | 242 return gfx::RectF(); |
233 | 243 |
234 return drawable_->GetVisibleBounds(); | 244 return drawable_->GetVisibleBounds(); |
235 } | 245 } |
236 | 246 |
247 gfx::PointF TouchHandle::GetHandleOrigin() const { | |
248 gfx::PointF position = mirror_vertical_ ? focus_top_ : focus_bottom_; | |
mfomitchev
2015/08/06 14:33:02
Call this "focus" instead of position? IMO positio
AviD
2015/08/09 13:55:41
Done.
| |
249 gfx::RectF drawable_bounds = drawable_->GetVisibleBounds(); | |
250 float drawable_width = drawable_->GetVisibleBounds().width(); | |
251 | |
252 // Set the Focal offsets for the composited handle layer | |
mfomitchev
2015/08/06 14:33:02
"focal offsets from origin"?
AviD
2015/08/09 13:55:41
Done.
| |
253 // based on the orientation | |
254 int focal_offset_x = 0; | |
255 int focal_offset_y = mirror_vertical_ ? drawable_bounds.height() : 0; | |
256 switch (orientation_) { | |
257 case ui::TouchHandleOrientation::LEFT: | |
258 focal_offset_x = | |
259 mirror_horizontal_ | |
260 ? drawable_width * handle_horizontal_padding_ | |
261 : drawable_width * (1.0f - handle_horizontal_padding_); | |
262 break; | |
263 case ui::TouchHandleOrientation::RIGHT: | |
264 focal_offset_x = | |
265 mirror_horizontal_ | |
266 ? drawable_width * (1.0f - handle_horizontal_padding_) | |
267 : drawable_width * handle_horizontal_padding_; | |
268 break; | |
269 case ui::TouchHandleOrientation::CENTER: | |
270 focal_offset_x = drawable_width * 0.5f; | |
271 break; | |
272 case ui::TouchHandleOrientation::UNDEFINED: | |
273 NOTREACHED() << "Invalid touch handle orientation."; | |
274 break; | |
275 }; | |
276 | |
277 gfx::Vector2dF offset_from_origin_ = | |
mfomitchev
2015/08/06 14:33:02
I'd just remove this variable and use the vector d
AviD
2015/08/09 13:55:41
Done.
| |
278 gfx::Vector2dF(focal_offset_x, focal_offset_y); | |
279 | |
280 return position - offset_from_origin_; | |
281 } | |
282 | |
283 void TouchHandle::UpdateHandleLayout() { | |
284 // Suppress repositioning a handle while invisible or fading out to prevent it | |
285 // from "ghosting" outside the visible bounds. The position will be pushed to | |
286 // the drawable when the handle regains visibility (see |SetVisible()|). | |
287 if (!is_visible_ || !is_handle_layout_update_required_) | |
288 return; | |
289 | |
290 is_handle_layout_update_required_ = false; | |
291 | |
292 // Update mirror values only when dragging has stopped to prevent unwanted | |
293 // inversion while dragging of handles | |
294 if (client_->IsEnabledAdaptiveHandleOrientation() && !is_dragging_) { | |
295 gfx::RectF handle_bounds = drawable_->GetVisibleBounds(); | |
296 bool mirror_horizontal = false; | |
297 bool mirror_vertical = false; | |
298 | |
299 const float handle_width = | |
300 handle_bounds.width() * (1.0 - handle_horizontal_padding_); | |
301 const float handle_height = handle_bounds.height(); | |
302 | |
303 const float bottom_y_unmirrored = | |
304 focus_bottom_.y() + handle_height + viewport_rect_.y(); | |
305 const float top_y_mirrored = | |
306 focus_top_.y() - handle_height + viewport_rect_.y(); | |
307 | |
308 // In case the viewport height is small, like webview, avoid inversion. | |
309 if (bottom_y_unmirrored > viewport_rect_.bottom() && | |
310 top_y_mirrored > viewport_rect_.y()) { | |
311 mirror_vertical = true; | |
312 } | |
313 | |
314 if (orientation_ == TouchHandleOrientation::LEFT && | |
315 focus_bottom_.x() - handle_width < viewport_rect_.x()) { | |
316 mirror_horizontal = true; | |
317 } else if (orientation_ == TouchHandleOrientation::RIGHT && | |
318 focus_bottom_.x() + handle_width > viewport_rect_.right()) { | |
319 mirror_horizontal = true; | |
320 } | |
321 | |
322 mirror_horizontal_ = mirror_horizontal; | |
323 mirror_vertical_ = mirror_vertical; | |
324 } | |
325 | |
326 drawable_->SetOrientation(orientation_, mirror_vertical_, mirror_horizontal_); | |
327 | |
328 gfx::PointF origin = GetHandleOrigin(); | |
329 drawable_->SetOrigin(origin); | |
330 } | |
331 | |
237 void TouchHandle::BeginDrag() { | 332 void TouchHandle::BeginDrag() { |
238 DCHECK(enabled_); | 333 DCHECK(enabled_); |
239 if (is_dragging_) | 334 if (is_dragging_) |
240 return; | 335 return; |
241 EndFade(); | 336 EndFade(); |
242 is_dragging_ = true; | 337 is_dragging_ = true; |
243 is_drag_within_tap_region_ = true; | 338 is_drag_within_tap_region_ = true; |
244 client_->OnDragBegin(*this, position()); | 339 client_->OnDragBegin(*this, focus_bottom()); |
245 } | 340 } |
246 | 341 |
247 void TouchHandle::EndDrag() { | 342 void TouchHandle::EndDrag() { |
248 DCHECK(enabled_); | 343 DCHECK(enabled_); |
249 if (!is_dragging_) | 344 if (!is_dragging_) |
250 return; | 345 return; |
251 | 346 |
252 is_dragging_ = false; | 347 is_dragging_ = false; |
253 is_drag_within_tap_region_ = false; | 348 is_drag_within_tap_region_ = false; |
254 client_->OnDragEnd(*this); | 349 client_->OnDragEnd(*this); |
255 | 350 |
256 if (deferred_orientation_ != TouchHandleOrientation::UNDEFINED) { | 351 if (deferred_orientation_ != TouchHandleOrientation::UNDEFINED) { |
257 TouchHandleOrientation deferred_orientation = deferred_orientation_; | 352 TouchHandleOrientation deferred_orientation = deferred_orientation_; |
258 deferred_orientation_ = TouchHandleOrientation::UNDEFINED; | 353 deferred_orientation_ = TouchHandleOrientation::UNDEFINED; |
259 SetOrientation(deferred_orientation); | 354 SetOrientation(deferred_orientation); |
355 // Handle layout may is deferred while the handle is dragged. | |
356 SetUpdateLayoutRequired(); | |
357 UpdateHandleLayout(); | |
260 } | 358 } |
261 | 359 |
262 if (animate_deferred_fade_) { | 360 if (animate_deferred_fade_) { |
263 BeginFade(); | 361 BeginFade(); |
264 } else { | 362 } else { |
265 // As drawable visibility assignment is deferred while dragging, push the | 363 // As drawable visibility assignment is deferred while dragging, push the |
266 // change by forcing fade completion. | 364 // change by forcing fade completion. |
267 EndFade(); | 365 EndFade(); |
268 } | 366 } |
269 } | 367 } |
270 | 368 |
271 void TouchHandle::BeginFade() { | 369 void TouchHandle::BeginFade() { |
272 DCHECK(enabled_); | 370 DCHECK(enabled_); |
273 DCHECK(!is_dragging_); | 371 DCHECK(!is_dragging_); |
274 animate_deferred_fade_ = false; | 372 animate_deferred_fade_ = false; |
275 const float target_alpha = is_visible_ ? 1.f : 0.f; | 373 const float target_alpha = is_visible_ ? 1.f : 0.f; |
276 if (target_alpha == alpha_) { | 374 if (target_alpha == alpha_) { |
277 EndFade(); | 375 EndFade(); |
278 return; | 376 return; |
279 } | 377 } |
280 | 378 |
281 fade_end_time_ = base::TimeTicks::Now() + | 379 fade_end_time_ = base::TimeTicks::Now() + |
282 base::TimeDelta::FromMillisecondsD( | 380 base::TimeDelta::FromMillisecondsD( |
283 kFadeDurationMs * std::abs(target_alpha - alpha_)); | 381 kFadeDurationMs * std::abs(target_alpha - alpha_)); |
284 fade_start_position_ = position_; | 382 fade_start_position_ = focus_bottom_; |
285 client_->SetNeedsAnimate(); | 383 client_->SetNeedsAnimate(); |
286 } | 384 } |
287 | 385 |
288 void TouchHandle::EndFade() { | 386 void TouchHandle::EndFade() { |
289 DCHECK(enabled_); | 387 DCHECK(enabled_); |
290 animate_deferred_fade_ = false; | 388 animate_deferred_fade_ = false; |
291 fade_end_time_ = base::TimeTicks(); | 389 fade_end_time_ = base::TimeTicks(); |
292 SetAlpha(is_visible_ ? 1.f : 0.f); | 390 SetAlpha(is_visible_ ? 1.f : 0.f); |
293 } | 391 } |
294 | 392 |
295 void TouchHandle::SetAlpha(float alpha) { | 393 void TouchHandle::SetAlpha(float alpha) { |
296 alpha = std::max(0.f, std::min(1.f, alpha)); | 394 alpha = std::max(0.f, std::min(1.f, alpha)); |
297 if (alpha_ == alpha) | 395 if (alpha_ == alpha) |
298 return; | 396 return; |
299 alpha_ = alpha; | 397 alpha_ = alpha; |
300 drawable_->SetAlpha(alpha); | 398 drawable_->SetAlpha(alpha); |
301 } | 399 } |
302 | 400 |
303 } // namespace ui | 401 } // namespace ui |
OLD | NEW |