app_drag_icon_proxy.cc 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  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 "ash/app_list/views/app_drag_icon_proxy.h"
  5. #include <utility>
  6. #include "ash/drag_drop/drag_image_view.h"
  7. #include "ash/public/cpp/style/color_provider.h"
  8. #include "ash/style/system_shadow.h"
  9. #include "ui/aura/window.h"
  10. #include "ui/base/dragdrop/mojom/drag_drop_types.mojom-shared.h"
  11. #include "ui/compositor/layer.h"
  12. #include "ui/compositor/scoped_layer_animation_settings.h"
  13. #include "ui/gfx/geometry/rect.h"
  14. #include "ui/gfx/geometry/rect_f.h"
  15. #include "ui/gfx/geometry/rounded_corners_f.h"
  16. #include "ui/gfx/geometry/size.h"
  17. #include "ui/gfx/geometry/transform_util.h"
  18. #include "ui/views/widget/widget.h"
  19. namespace ash {
  20. constexpr SystemShadow::Type kShadowType = SystemShadow::Type::kElevation12;
  21. // For all app icons, there is an intended transparent ring around the visible
  22. // icon that makes the icon looks smaller than its actual size. The shadow is
  23. // needed to resize to align with the visual icon. Note that this constant is
  24. // the same as `kBackgroundCircleScale` in
  25. // chrome/browser/apps/icon_standardizer.cc
  26. constexpr float kShadowScaleFactor = 176.f / 192.f;
  27. AppDragIconProxy::AppDragIconProxy(
  28. aura::Window* root_window,
  29. const gfx::ImageSkia& icon,
  30. const gfx::Point& pointer_location_in_screen,
  31. const gfx::Vector2d& pointer_offset_from_center,
  32. float scale_factor,
  33. bool use_blurred_background) {
  34. drag_image_widget_ =
  35. DragImageView::Create(root_window, ui::mojom::DragEventSource::kMouse);
  36. DragImageView* drag_image =
  37. static_cast<DragImageView*>(drag_image_widget_->GetContentsView());
  38. drag_image->SetImage(icon);
  39. gfx::Size size = drag_image->GetPreferredSize();
  40. size.set_width(std::round(size.width() * scale_factor));
  41. size.set_height(std::round(size.height() * scale_factor));
  42. drag_image_offset_ = gfx::Vector2d(size.width() / 2, size.height() / 2) +
  43. pointer_offset_from_center;
  44. gfx::Rect drag_image_bounds(pointer_location_in_screen - drag_image_offset_,
  45. size);
  46. drag_image->SetBoundsInScreen(drag_image_bounds);
  47. // Add a layer in order to ensure the icon properly animates when
  48. // `AnimateToBoundsAndCloseWidget()` gets called. Layer is also required when
  49. // setting blur radius.
  50. drag_image->SetPaintToLayer();
  51. drag_image->layer()->SetFillsBoundsOpaquely(false);
  52. // Create the shadow layer.
  53. gfx::Size shadow_size = gfx::ScaleToFlooredSize(size, kShadowScaleFactor);
  54. gfx::Point shadow_offset((size.width() - shadow_size.width()) / 2,
  55. (size.height() - shadow_size.height()) / 2);
  56. shadow_ = SystemShadow::CreateShadowOnTextureLayer(kShadowType);
  57. shadow_->SetRoundedCornerRadius(shadow_size.width() / 2);
  58. auto* shadow_layer = shadow_->GetLayer();
  59. auto* image_layer = drag_image->layer();
  60. image_layer->Add(shadow_layer);
  61. image_layer->StackAtBottom(shadow_layer);
  62. shadow_->SetContentBounds(gfx::Rect(shadow_offset, shadow_size));
  63. if (use_blurred_background) {
  64. const float radius = size.width() / 2.0f;
  65. drag_image->layer()->SetRoundedCornerRadius(
  66. {radius, radius, radius, radius});
  67. drag_image->layer()->SetBackgroundBlur(ColorProvider::kBackgroundBlurSigma);
  68. drag_image->layer()->SetBackdropFilterQuality(
  69. ColorProvider::kBackgroundBlurQuality);
  70. }
  71. drag_image_widget_->SetVisibilityAnimationTransition(
  72. views::Widget::ANIMATE_NONE);
  73. drag_image->SetWidgetVisible(true);
  74. }
  75. AppDragIconProxy::~AppDragIconProxy() {
  76. StopObservingImplicitAnimations();
  77. if (animation_completion_callback_)
  78. std::move(animation_completion_callback_).Run();
  79. }
  80. void AppDragIconProxy::UpdatePosition(
  81. const gfx::Point& pointer_location_in_screen) {
  82. // TODO(jennyz): Investigate why drag_image_widget_ becomes null at this point
  83. // per crbug.com/34722, while the app list item is still being dragged around.
  84. if (drag_image_widget_ && !closing_widget_) {
  85. static_cast<DragImageView*>(drag_image_widget_->GetContentsView())
  86. ->SetScreenPosition(pointer_location_in_screen - drag_image_offset_);
  87. }
  88. }
  89. void AppDragIconProxy::AnimateToBoundsAndCloseWidget(
  90. const gfx::Rect& bounds_in_screen,
  91. base::OnceClosure animation_completion_callback) {
  92. DCHECK(!closing_widget_);
  93. DCHECK(!animation_completion_callback_);
  94. animation_completion_callback_ = std::move(animation_completion_callback);
  95. closing_widget_ = true;
  96. // Prevent any in progress animations from interfering with the timing on the
  97. // animation completion callback.
  98. ui::Layer* target_layer = drag_image_widget_->GetContentsView()->layer();
  99. target_layer->GetAnimator()->AbortAllAnimations();
  100. gfx::Rect current_bounds = GetBoundsInScreen();
  101. if (current_bounds.IsEmpty()) {
  102. drag_image_widget_.reset();
  103. if (animation_completion_callback_)
  104. std::move(animation_completion_callback_).Run();
  105. return;
  106. }
  107. ui::ScopedLayerAnimationSettings animation_settings(
  108. target_layer->GetAnimator());
  109. animation_settings.SetTweenType(gfx::Tween::FAST_OUT_LINEAR_IN);
  110. animation_settings.SetPreemptionStrategy(
  111. ui::LayerAnimator::IMMEDIATELY_SET_NEW_TARGET);
  112. animation_settings.AddObserver(this);
  113. target_layer->SetTransform(gfx::TransformBetweenRects(
  114. gfx::RectF(GetBoundsInScreen()), gfx::RectF(bounds_in_screen)));
  115. }
  116. void AppDragIconProxy::OnImplicitAnimationsCompleted() {
  117. StopObserving();
  118. drag_image_widget_.reset();
  119. if (animation_completion_callback_)
  120. std::move(animation_completion_callback_).Run();
  121. }
  122. gfx::Rect AppDragIconProxy::GetBoundsInScreen() const {
  123. if (!drag_image_widget_)
  124. return gfx::Rect();
  125. return drag_image_widget_->GetContentsView()->GetBoundsInScreen();
  126. }
  127. void AppDragIconProxy::SetOpacity(float opacity) {
  128. if (drag_image_widget_ && !closing_widget_)
  129. drag_image_widget_->GetContentsView()->layer()->SetOpacity(opacity);
  130. }
  131. ui::Layer* AppDragIconProxy::GetImageLayerForTesting() {
  132. return drag_image_widget_->GetContentsView()->layer();
  133. }
  134. views::Widget* AppDragIconProxy::GetWidgetForTesting() {
  135. return drag_image_widget_.get();
  136. }
  137. } // namespace ash