| 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); |
| 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 Loading... |
| 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 |
| OLD | NEW |