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 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, false); |
80 drawable_->SetAlpha(alpha_); | 84 drawable_->SetAlpha(alpha_); |
81 drawable_->SetFocus(position_); | |
82 } | 85 } |
83 | 86 |
84 TouchHandle::~TouchHandle() { | 87 TouchHandle::~TouchHandle() { |
85 } | 88 } |
86 | 89 |
87 void TouchHandle::SetEnabled(bool enabled) { | 90 void TouchHandle::SetEnabled(bool enabled) { |
88 if (enabled_ == enabled) | 91 if (enabled_ == enabled) |
89 return; | 92 return; |
90 if (!enabled) { | 93 if (!enabled) { |
91 EndDrag(); | 94 EndDrag(); |
92 EndFade(); | 95 EndFade(); |
93 } | 96 } |
94 enabled_ = enabled; | 97 enabled_ = enabled; |
95 drawable_->SetEnabled(enabled); | 98 drawable_->SetEnabled(enabled); |
96 } | 99 } |
97 | 100 |
98 void TouchHandle::SetVisible(bool visible, AnimationStyle animation_style) { | 101 void TouchHandle::SetVisible(bool visible, AnimationStyle animation_style) { |
99 DCHECK(enabled_); | 102 DCHECK(enabled_); |
100 if (is_visible_ == visible) | 103 if (is_visible_ == visible) |
101 return; | 104 return; |
102 | 105 |
103 is_visible_ = visible; | 106 is_visible_ = visible; |
104 | 107 |
105 // Handle repositioning may have been deferred while previously invisible. | 108 // Handle repositioning may have been deferred while previously invisible. |
106 if (visible) | 109 UpdateLayout(); |
107 drawable_->SetFocus(position_); | |
108 | 110 |
109 bool animate = animation_style != ANIMATION_NONE; | 111 bool animate = animation_style != ANIMATION_NONE; |
110 if (is_dragging_) { | 112 if (is_dragging_) { |
111 animate_deferred_fade_ = animate; | 113 animate_deferred_fade_ = animate; |
112 return; | 114 return; |
113 } | 115 } |
114 | 116 |
115 if (animate) | 117 if (animate) |
116 BeginFade(); | 118 BeginFade(); |
117 else | 119 else |
118 EndFade(); | 120 EndFade(); |
119 } | 121 } |
120 | 122 |
121 void TouchHandle::SetPosition(const gfx::PointF& position) { | 123 void TouchHandle::SetFocus(const gfx::PointF& top, const gfx::PointF& bottom) { |
122 DCHECK(enabled_); | 124 if (focus_top_ == top && focus_bottom_ == bottom) |
123 if (position_ == position) | |
124 return; | 125 return; |
125 position_ = position; | 126 |
126 // Suppress repositioning a handle while invisible or fading out to prevent it | 127 focus_top_ = top; |
127 // from "ghosting" outside the visible bounds. The position will be pushed to | 128 focus_bottom_ = bottom; |
128 // the drawable when the handle regains visibility (see |SetVisible()|). | 129 UpdateLayout(); |
129 if (is_visible_) | 130 } |
130 drawable_->SetFocus(position_); | 131 |
132 void TouchHandle::SetViewportRect(const gfx::RectF viewport_rect) { | |
133 if ((viewport_rect_ == viewport_rect)) | |
jdduke (slow)
2015/06/08 15:24:46
Nit: No need for double parentheses.
AviD
2015/06/16 14:09:14
Done.
| |
134 return; | |
135 | |
136 viewport_rect_ = viewport_rect; | |
137 UpdateLayout(); | |
131 } | 138 } |
132 | 139 |
133 void TouchHandle::SetOrientation(TouchHandleOrientation orientation) { | 140 void TouchHandle::SetOrientation(TouchHandleOrientation orientation) { |
134 DCHECK(enabled_); | 141 DCHECK(enabled_); |
135 DCHECK_NE(orientation, TouchHandleOrientation::UNDEFINED); | 142 DCHECK_NE(orientation, TouchHandleOrientation::UNDEFINED); |
136 if (is_dragging_) { | 143 if (is_dragging_) { |
137 deferred_orientation_ = orientation; | 144 deferred_orientation_ = orientation; |
138 return; | 145 return; |
139 } | 146 } |
140 DCHECK_EQ(deferred_orientation_, TouchHandleOrientation::UNDEFINED); | 147 DCHECK_EQ(deferred_orientation_, TouchHandleOrientation::UNDEFINED); |
141 if (orientation_ == orientation) | 148 if (orientation_ == orientation) |
142 return; | 149 return; |
143 | 150 |
144 orientation_ = orientation; | 151 orientation_ = orientation; |
145 drawable_->SetOrientation(orientation); | 152 UpdateLayout(); |
146 } | 153 } |
147 | 154 |
148 bool TouchHandle::WillHandleTouchEvent(const MotionEvent& event) { | 155 bool TouchHandle::WillHandleTouchEvent(const MotionEvent& event) { |
149 if (!enabled_) | 156 if (!enabled_) |
150 return false; | 157 return false; |
151 | 158 |
152 if (!is_dragging_ && event.GetAction() != MotionEvent::ACTION_DOWN) | 159 if (!is_dragging_ && event.GetAction() != MotionEvent::ACTION_DOWN) |
153 return false; | 160 return false; |
154 | 161 |
155 switch (event.GetAction()) { | 162 switch (event.GetAction()) { |
156 case MotionEvent::ACTION_DOWN: { | 163 case MotionEvent::ACTION_DOWN: { |
157 if (!is_visible_) | 164 if (!is_visible_) |
158 return false; | 165 return false; |
159 const gfx::PointF touch_point(event.GetX(), event.GetY()); | 166 const gfx::PointF touch_point(event.GetX(), event.GetY()); |
160 const float touch_radius = std::max( | 167 const float touch_radius = std::max( |
161 kMinTouchMajorForHitTesting, | 168 kMinTouchMajorForHitTesting, |
162 std::min(kMaxTouchMajorForHitTesting, event.GetTouchMajor())) * 0.5f; | 169 std::min(kMaxTouchMajorForHitTesting, event.GetTouchMajor())) * 0.5f; |
163 if (!RectIntersectsCircle(drawable_->GetVisibleBounds(), | 170 if (!RectIntersectsCircle(drawable_->GetVisibleBounds(), |
164 touch_point, | 171 touch_point, |
165 touch_radius)) { | 172 touch_radius)) { |
166 EndDrag(); | 173 EndDrag(); |
167 return false; | 174 return false; |
168 } | 175 } |
169 touch_down_position_ = touch_point; | 176 touch_down_position_ = touch_point; |
170 touch_to_focus_offset_ = position_ - touch_down_position_; | 177 touch_to_focus_offset_ = focus_bottom_ - touch_down_position_; |
171 touch_down_time_ = event.GetEventTime(); | 178 touch_down_time_ = event.GetEventTime(); |
172 BeginDrag(); | 179 BeginDrag(); |
173 } break; | 180 } break; |
174 | 181 |
175 case MotionEvent::ACTION_MOVE: { | 182 case MotionEvent::ACTION_MOVE: { |
176 gfx::PointF touch_move_position(event.GetX(), event.GetY()); | 183 gfx::PointF touch_move_position(event.GetX(), event.GetY()); |
177 if (is_drag_within_tap_region_) { | 184 if (is_drag_within_tap_region_) { |
178 const float tap_slop = client_->GetTapSlop(); | 185 const float tap_slop = client_->GetTapSlop(); |
179 is_drag_within_tap_region_ = | 186 is_drag_within_tap_region_ = |
180 (touch_move_position - touch_down_position_).LengthSquared() < | 187 (touch_move_position - touch_down_position_).LengthSquared() < |
(...skipping 27 matching lines...) Expand all Loading... | |
208 } | 215 } |
209 | 216 |
210 bool TouchHandle::Animate(base::TimeTicks frame_time) { | 217 bool TouchHandle::Animate(base::TimeTicks frame_time) { |
211 if (fade_end_time_ == base::TimeTicks()) | 218 if (fade_end_time_ == base::TimeTicks()) |
212 return false; | 219 return false; |
213 | 220 |
214 DCHECK(enabled_); | 221 DCHECK(enabled_); |
215 | 222 |
216 float time_u = | 223 float time_u = |
217 1.f - (fade_end_time_ - frame_time).InMillisecondsF() / kFadeDurationMs; | 224 1.f - (fade_end_time_ - frame_time).InMillisecondsF() / kFadeDurationMs; |
218 float position_u = | 225 float position_u = (focus_bottom_ - fade_start_position_).LengthSquared() / |
219 (position_ - fade_start_position_).LengthSquared() / kFadeDistanceSquared; | 226 kFadeDistanceSquared; |
220 float u = std::max(time_u, position_u); | 227 float u = std::max(time_u, position_u); |
221 SetAlpha(is_visible_ ? u : 1.f - u); | 228 SetAlpha(is_visible_ ? u : 1.f - u); |
222 | 229 |
223 if (u >= 1.f) { | 230 if (u >= 1.f) { |
224 EndFade(); | 231 EndFade(); |
225 return false; | 232 return false; |
226 } | 233 } |
227 | 234 |
228 return true; | 235 return true; |
229 } | 236 } |
230 | 237 |
231 gfx::RectF TouchHandle::GetVisibleBounds() const { | 238 gfx::RectF TouchHandle::GetVisibleBounds() const { |
232 if (!is_visible_ || !enabled_) | 239 if (!is_visible_ || !enabled_) |
233 return gfx::RectF(); | 240 return gfx::RectF(); |
234 | 241 |
235 return drawable_->GetVisibleBounds(); | 242 return drawable_->GetVisibleBounds(); |
236 } | 243 } |
237 | 244 |
245 void TouchHandle::UpdateLayout() { | |
246 // Suppress repositioning a handle while invisible or fading out to prevent it | |
247 // from "ghosting" outside the visible bounds. The position will be pushed to | |
248 // the drawable when the handle regains visibility (see |SetVisible()|). | |
249 if (!is_visible_) | |
250 return; | |
251 | |
252 // Update mirror values only when dragging has stopped to prevent unwanted | |
253 // inversion while dragging of handles | |
254 bool mirror_changed = false; | |
255 | |
256 if (!is_dragging_) { | |
257 gfx::RectF handle_bounds = drawable_->GetVisibleBounds(); | |
258 bool mirror_horizontal = false; | |
259 bool mirror_vertical = false; | |
260 | |
261 const float bottom_y_unmirrored = | |
262 focus_bottom_.y() + handle_bounds.height() + viewport_rect_.y(); | |
263 const float top_y_mirrored = | |
264 focus_top_.y() - handle_bounds.height() + viewport_rect_.y(); | |
265 | |
266 // In case the viewport height is small, like webview, avoid inversion. | |
267 if (bottom_y_unmirrored > viewport_rect_.bottom() && | |
268 top_y_mirrored > viewport_rect_.y()) { | |
269 mirror_vertical = true; | |
mfomitchev
2015/06/08 18:06:09
Don't we also have vertical padding to account for
AviD
2015/06/16 14:09:14
Added a common API to get both vertical and horizo
| |
270 } | |
271 | |
272 if (orientation_ == TouchHandleOrientation::LEFT && | |
273 focus_bottom_.x() - (handle_bounds.width() * 0.75f) < | |
mfomitchev
2015/06/08 18:06:09
This code will be used by Aura (desktop Chrome UI)
AviD
2015/06/16 14:09:14
I have added GetDrawablePadding() returning gfx::S
| |
274 viewport_rect_.x()) { | |
275 mirror_horizontal = true; | |
276 } else if (orientation_ == TouchHandleOrientation::RIGHT && | |
277 focus_bottom_.x() + (handle_bounds.width() * 0.75f) > | |
278 viewport_rect_.right()) { | |
279 mirror_horizontal = true; | |
280 } | |
281 | |
282 mirror_changed = mirror_horizontal != mirror_horizontal_ || | |
283 mirror_vertical != mirror_vertical_; | |
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_, mirror_changed); | |
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 |
OLD | NEW |