bubble_slide_animator.cc 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112
  1. // Copyright 2021 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. #include "ui/views/animation/bubble_slide_animator.h"
  5. #include "base/time/time.h"
  6. #include "ui/views/bubble/bubble_dialog_delegate_view.h"
  7. namespace views {
  8. BubbleSlideAnimator::BubbleSlideAnimator(
  9. BubbleDialogDelegateView* bubble_delegate)
  10. : AnimationDelegateViews(bubble_delegate),
  11. bubble_delegate_(bubble_delegate) {
  12. Widget* widget = bubble_delegate->GetWidget();
  13. DCHECK(widget);
  14. widget_observation_.Observe(widget);
  15. constexpr base::TimeDelta kDefaultBubbleSlideAnimationTime =
  16. base::Milliseconds(200);
  17. slide_animation_.SetDuration(kDefaultBubbleSlideAnimationTime);
  18. }
  19. BubbleSlideAnimator::~BubbleSlideAnimator() = default;
  20. void BubbleSlideAnimator::SetSlideDuration(base::TimeDelta duration) {
  21. slide_animation_.SetDuration(duration);
  22. }
  23. void BubbleSlideAnimator::AnimateToAnchorView(View* desired_anchor_view) {
  24. desired_anchor_view_ = desired_anchor_view;
  25. starting_bubble_bounds_ =
  26. bubble_delegate_->GetWidget()->GetWindowBoundsInScreen();
  27. target_bubble_bounds_ = CalculateTargetBounds(desired_anchor_view);
  28. slide_animation_.SetCurrentValue(0);
  29. slide_animation_.Start();
  30. }
  31. void BubbleSlideAnimator::SnapToAnchorView(View* desired_anchor_view) {
  32. StopAnimation();
  33. target_bubble_bounds_ = CalculateTargetBounds(desired_anchor_view);
  34. starting_bubble_bounds_ = target_bubble_bounds_;
  35. bubble_delegate_->GetWidget()->SetBounds(target_bubble_bounds_);
  36. bubble_delegate_->SetAnchorView(desired_anchor_view);
  37. slide_progressed_callbacks_.Notify(this, 1.0);
  38. slide_complete_callbacks_.Notify(this);
  39. }
  40. void BubbleSlideAnimator::UpdateTargetBounds() {
  41. if (is_animating()) {
  42. // This will cause a mid-animation pop due to the fact that we're not
  43. // resetting the starting bounds but it's not clear that it's a better
  44. // solution than rewinding and/or changing the duration of the animation.
  45. target_bubble_bounds_ = CalculateTargetBounds(desired_anchor_view_);
  46. } else {
  47. View* const anchor_view = bubble_delegate_->GetAnchorView();
  48. DCHECK(anchor_view);
  49. SnapToAnchorView(anchor_view);
  50. }
  51. }
  52. void BubbleSlideAnimator::StopAnimation() {
  53. slide_animation_.Stop();
  54. desired_anchor_view_ = nullptr;
  55. }
  56. base::CallbackListSubscription BubbleSlideAnimator::AddSlideProgressedCallback(
  57. SlideProgressedCallback callback) {
  58. return slide_progressed_callbacks_.Add(callback);
  59. }
  60. base::CallbackListSubscription BubbleSlideAnimator::AddSlideCompleteCallback(
  61. SlideCompleteCallback callback) {
  62. return slide_complete_callbacks_.Add(callback);
  63. }
  64. void BubbleSlideAnimator::AnimationProgressed(const gfx::Animation* animation) {
  65. double value = gfx::Tween::CalculateValue(tween_type_,
  66. slide_animation_.GetCurrentValue());
  67. const gfx::Rect current_bounds = gfx::Tween::RectValueBetween(
  68. value, starting_bubble_bounds_, target_bubble_bounds_);
  69. if (current_bounds == target_bubble_bounds_ && desired_anchor_view_)
  70. bubble_delegate_->SetAnchorView(desired_anchor_view_);
  71. bubble_delegate_->GetWidget()->SetBounds(current_bounds);
  72. slide_progressed_callbacks_.Notify(this, value);
  73. }
  74. void BubbleSlideAnimator::AnimationEnded(const gfx::Animation* animation) {
  75. desired_anchor_view_ = nullptr;
  76. slide_complete_callbacks_.Notify(this);
  77. }
  78. void BubbleSlideAnimator::AnimationCanceled(const gfx::Animation* animation) {
  79. desired_anchor_view_ = nullptr;
  80. }
  81. void BubbleSlideAnimator::OnWidgetDestroying(Widget* widget) {
  82. widget_observation_.Reset();
  83. slide_animation_.Stop();
  84. }
  85. gfx::Rect BubbleSlideAnimator::CalculateTargetBounds(
  86. const View* desired_anchor_view) const {
  87. return bubble_delegate_->GetBubbleFrameView()->GetUpdatedWindowBounds(
  88. desired_anchor_view->GetAnchorBoundsInScreen(), bubble_delegate_->arrow(),
  89. bubble_delegate_->GetWidget()->client_view()->GetPreferredSize(), true);
  90. }
  91. } // namespace views