chromium/ash/app_list/views/app_drag_icon_proxy.h

// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef ASH_APP_LIST_VIEWS_APP_DRAG_ICON_PROXY_H_
#define ASH_APP_LIST_VIEWS_APP_DRAG_ICON_PROXY_H_

#include <memory>
#include "ash/style/system_shadow.h"
#include "base/functional/callback.h"
#include "ui/compositor/layer_animation_observer.h"
#include "ui/gfx/geometry/vector2d.h"
#include "ui/views/widget/unique_widget_ptr.h"

namespace aura {
class Window;
}  // namespace aura

namespace gfx {
class ImageSkia;
class Point;
class Rect;
}  // namespace gfx

namespace ui {
class Layer;
class LayerOwner;
}  // namespace ui

namespace ash {

// Manages the drag image shown while an app is being dragged in app list or
// shelf. It creates a DragImageView widget in a window container used for
// drag images, so the app icon can escape the views container that owns the
// dragged app view. The widget is destroyed when this goes out of scope.
class AppDragIconProxy {
 public:
  // `root_window` - The root window to which the proxy should be added.
  // `icon` - The icon to be used for the app icon.
  // `badge_icon` - If non-empty, the badge icon to be overlaied over the app
  //     icon.
  // `pointer_location_in_screen` - The initial pointer location.
  // `pointer_offset_from_center` - The pointer offset from the center of the
  //     drag image. The drag icon position will be offset from the pointer
  //     location to maintain pointer offset from the drag image center.
  // `scale_factor` - The scale factor by which the `icon` should be scaled when
  //     shown as a drag image.
  // `is_folder_icon` - whether the icon dragged is a folder.
  // `shadow_size` - specify the size of the shadow, which will be drawn at the
  // center of the icon proxy.
  AppDragIconProxy(aura::Window* root_window,
                   const gfx::ImageSkia& icon,
                   const gfx::ImageSkia& badge_icon,
                   const gfx::Point& pointer_location_in_screen,
                   const gfx::Vector2d& pointer_offset_from_center,
                   float scale_factor,
                   bool is_folder_icon,
                   const gfx::Size& shadow_size);
  AppDragIconProxy(const AppDragIconProxy&) = delete;
  AppDragIconProxy& operator=(const AppDragIconProxy&) = delete;
  ~AppDragIconProxy();

  // Updates drag icon position to match the new pointer location.
  void UpdatePosition(const gfx::Point& pointer_location_in_screen);

  // Animates the drag image to the provided bounds, and closes the widget once
  // the animation completes. Expected to be called at most once.
  // `animation_completion_callback` - Called when the animation completes, or
  // when the `AppDragIconProxy` gets deleted.
  void AnimateToBoundsAndCloseWidget(
      const gfx::Rect& bounds_in_screen,
      base::OnceClosure animation_completion_callback);

  // Sets the drag image opacity.
  void SetOpacity(float opacity);

  // Returns the current drag image bounds in screen.
  gfx::Rect GetBoundsInScreen() const;

  // Returns the drag image view's layer.
  ui::Layer* GetImageLayerForTesting();

  // Returns the drag image widget.
  views::Widget* GetWidgetForTesting();

  gfx::Rect shadow_bounds_for_testing() const {
    return shadow_->GetContentBounds();
  }

  // Returns the layer that is used to blur the background.
  ui::Layer* GetBlurredLayerForTesting();

 private:
  void OnProxyAnimationCompleted();

  // Whether close animation (see `AnimateToBoundsAndCloseWidget()`) is in
  // progress.
  bool closing_widget_ = false;

  std::unique_ptr<SystemShadow> shadow_;

  // A layer that is used to blur the background of the dragged icon. Only used
  // for refreshed folder icons.
  std::unique_ptr<ui::LayerOwner> blurred_background_layer_;

  // The widget used to display the drag image.
  views::UniqueWidgetPtr drag_image_widget_;

  // The cursor offset to the center of the dragged item.
  gfx::Vector2d drag_image_offset_;

  base::OnceClosure animation_completion_callback_;

  base::WeakPtrFactory<AppDragIconProxy> weak_ptr_factory_{this};
};

}  // namespace ash

#endif  // ASH_APP_LIST_VIEWS_APP_DRAG_ICON_PROXY_H_