Skip to content

Commit

Permalink
Expose the drag image on drop callback
Browse files Browse the repository at this point in the history
The proposed cl, attaches a new callback similar to the regular drop
callback, but with the intention to access the drag image layer that in
turn, the view where an item is dropped will be able to animate.

DragDropController recreates the old drag image layer into its own layer
owner, which will be passed around to the object that requests it.

The implementations of DragDropDelegate and views::View will be able to
define the appropriate callback that will be invoked always preferring
an existing DropCallback over DropCallbackWithAnimation.  The drag and
drop controller is modified to invoke the appropriate callback and to
pass the drag image layer owner through this invocation if needed.

This CL also moves DragImageView to create a unique_ptr<views::Widget>
rather than a UniqueWidgetPtr.

Bug: b:261985897
Change-Id: Ia4c049f3a80c9c7bac76d873827ce1f015af5088
Low-Coverage-Reason: virtual methods
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4264073
Reviewed-by: Mitsuru Oshima <oshima@chromium.org>
Commit-Queue: Ana Salazar <anasalazar@chromium.org>
Reviewed-by: Allen Bauer <kylixrd@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1109259}
  • Loading branch information
Ana Salazar authored and Chromium LUCI CQ committed Feb 23, 2023
1 parent 8b4eed3 commit 40d497c
Show file tree
Hide file tree
Showing 12 changed files with 137 additions and 18 deletions.
25 changes: 17 additions & 8 deletions ash/drag_drop/drag_drop_controller.cc
Original file line number Diff line number Diff line change
Expand Up @@ -619,15 +619,19 @@ void DragDropController::Drop(aura::Window* target,
aura::client::GetDragDropDelegate(target);

aura::client::DragDropDelegate::DropCallback delegate_drop_cb =
base::DoNothing();
base::NullCallback();
aura::client::DragDropDelegate::DropCallbackWithAnimation
delegate_drop_cb_animation = base::NullCallback();

ui::DropTargetEvent e(*drag_data_.get(), event.location_f(),
event.root_location_f(), allowed_operations_);
e.set_flags(event.flags());
ui::Event::DispatcherApi(&e).set_target(target);

if (delegate)
if (delegate) {
delegate_drop_cb_animation = delegate->GetDropCallbackWithAnimation(e);
delegate_drop_cb = delegate->GetDropCallback(e);
}

base::ScopedClosureRunner drag_cancel(base::BindOnce(
&DragDropController::DragCancel, weak_factory_.GetWeakPtr()));
Expand All @@ -642,11 +646,11 @@ void DragDropController::Drop(aura::Window* target,

DropIfAllowed(
drag_data_.get(), current_drag_info_,
base::BindOnce(&DragDropController::PerformDrop,
weak_factory_.GetWeakPtr(), drop_location_in_screen, e,
std::move(drag_data_), std::move(delegate_drop_cb),
std::move(tab_drag_drop_delegate_),
std::move(drag_cancel)));
base::BindOnce(
&DragDropController::PerformDrop, weak_factory_.GetWeakPtr(),
drop_location_in_screen, e, std::move(drag_data_),
std::move(delegate_drop_cb), std::move(delegate_drop_cb_animation),
std::move(tab_drag_drop_delegate_), std::move(drag_cancel)));

// During the drop, the event target (or its ancestors) might have
// been destroyed, eg by the client reaction. Adapt the DropTargetEvent
Expand Down Expand Up @@ -820,6 +824,7 @@ void DragDropController::PerformDrop(
ui::DropTargetEvent event,
std::unique_ptr<ui::OSExchangeData> drag_data,
aura::client::DragDropDelegate::DropCallback drop_cb,
aura::client::DragDropDelegate::DropCallbackWithAnimation drop_cb_animation,
std::unique_ptr<TabDragDropDelegate> tab_drag_drop_delegate,
base::ScopedClosureRunner drag_cancel) {
// Event copy constructor dooesn't copy the target. That's why we set it here.
Expand All @@ -828,7 +833,11 @@ void DragDropController::PerformDrop(
ui::Event::DispatcherApi(&event).set_target(drag_window_);

ui::OSExchangeData copied_data(drag_data->provider().Clone());
if (drop_cb) {
if (!!drop_cb_animation) {
std::move(drop_cb_animation)
.Run(std::move(drag_data), operation_,
::wm::RecreateLayers(drag_image_widget_->GetNativeWindow()));
} else if (!!drop_cb) {
std::move(drop_cb).Run(std::move(drag_data), operation_);
}

Expand Down
4 changes: 3 additions & 1 deletion ash/drag_drop/drag_drop_controller.h
Original file line number Diff line number Diff line change
Expand Up @@ -166,14 +166,16 @@ class ASH_EXPORT DragDropController : public aura::client::DragDropClient,
ui::DropTargetEvent event,
std::unique_ptr<ui::OSExchangeData> drag_data,
aura::client::DragDropDelegate::DropCallback drop_cb,
aura::client::DragDropDelegate::DropCallbackWithAnimation
drop_cb_animation,
std::unique_ptr<TabDragDropDelegate> tab_drag_drop_delegate,
base::ScopedClosureRunner drag_cancel);

void CancelIfInProgress();

bool enabled_ = false;
bool drag_drop_completed_ = true;
views::UniqueWidgetPtr drag_image_widget_;
std::unique_ptr<views::Widget> drag_image_widget_;
gfx::Vector2d drag_image_offset_;
std::unique_ptr<ui::OSExchangeData> drag_data_;
int allowed_operations_ = 0;
Expand Down
6 changes: 3 additions & 3 deletions ash/drag_drop/drag_image_view.cc
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ DragImageView::DragImageView(ui::mojom::DragEventSource event_source)
DragImageView::~DragImageView() = default;

// static
views::UniqueWidgetPtr DragImageView::Create(
std::unique_ptr<views::Widget> DragImageView::Create(
aura::Window* root_window,
ui::mojom::DragEventSource event_source) {
views::Widget::InitParams params;
Expand All @@ -37,12 +37,12 @@ views::UniqueWidgetPtr DragImageView::Create(
params.accept_events = false;
params.shadow_type = views::Widget::InitParams::ShadowType::kNone;
params.opacity = views::Widget::InitParams::WindowOpacity::kTranslucent;
params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
params.parent =
root_window->GetChildById(kShellWindowId_DragImageAndTooltipContainer);
if (!params.parent)
params.context = root_window; // Happens in tests.
auto drag_widget = views::UniqueWidgetPtr(
std::make_unique<views::Widget>(std::move(params)));
auto drag_widget = std::make_unique<views::Widget>(std::move(params));
drag_widget->SetOpacity(1.f);
drag_widget->SetContentsView(
base::WrapUnique(new DragImageView(event_source)));
Expand Down
6 changes: 3 additions & 3 deletions ash/drag_drop/drag_image_view.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
#include "ui/gfx/geometry/point.h"
#include "ui/gfx/geometry/size.h"
#include "ui/views/controls/image_view.h"
#include "ui/views/widget/unique_widget_ptr.h"

namespace aura {
class Window;
Expand All @@ -38,8 +37,9 @@ class ASH_EXPORT DragImageView : public views::ImageView {
// |source| is the event source that started this drag drop operation (touch
// or mouse). It is used to determine attributes of the drag image such as
// whether to show drag operation hint on top of the image.
static views::UniqueWidgetPtr Create(aura::Window* root_window,
ui::mojom::DragEventSource source);
static std::unique_ptr<views::Widget> Create(
aura::Window* root_window,
ui::mojom::DragEventSource source);

// Sets the bounds of the native widget in screen
// coordinates.
Expand Down
6 changes: 6 additions & 0 deletions ui/aura/client/drag_drop_delegate.cc
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,12 @@ DragUpdateInfo& DragUpdateInfo::operator=(const DragUpdateInfo& update_info) =

DEFINE_UI_CLASS_PROPERTY_KEY(DragDropDelegate*, kDragDropDelegateKey, nullptr)

DragDropDelegate::DropCallbackWithAnimation
DragDropDelegate::GetDropCallbackWithAnimation(
const ui::DropTargetEvent& event) {
return base::NullCallback();
}

void SetDragDropDelegate(Window* window, DragDropDelegate* delegate) {
window->SetProperty(kDragDropDelegateKey, delegate);
}
Expand Down
19 changes: 16 additions & 3 deletions ui/aura/client/drag_drop_delegate.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@

namespace ui {
class DropTargetEvent;
}
class LayerTreeOwner;
} // namespace ui

namespace aura {
class Window;
Expand Down Expand Up @@ -46,6 +47,13 @@ class AURA_EXPORT DragDropDelegate {
base::OnceCallback<void(std::unique_ptr<ui::OSExchangeData> data,
ui::mojom::DragOperation& output_drag_op)>;

// Callback emitted by GetDropCallbackWithAnimation used to handle deferred
// drop events and drag image dropping animation.
using DropCallbackWithAnimation = base::OnceCallback<void(
std::unique_ptr<ui::OSExchangeData> data,
ui::mojom::DragOperation& output_drag_op,
std::unique_ptr<ui::LayerTreeOwner> old_layer_owner)>;

// OnDragEntered is invoked when the mouse enters this window during a drag &
// drop session. This is immediately followed by an invocation of
// OnDragUpdated, and eventually one of OnDragExited, or GetDropCallback.
Expand All @@ -62,9 +70,14 @@ class AURA_EXPORT DragDropDelegate {

// Invoked during a drag and drop session when the user release the mouse, but
// the drop is held because of the DataTransferPolicyController.
// The returned callback may be NullCallback if there's nothing to do and the
// drop event is ignored.
// The implementation may support different a callback to obtain a drag image
// widget and manipulate the dropping animation when
// GetDropCallbackWithAnimation returns base::NullCallback(). Otherwise, the
// implementation will fallback to the default GetDropCallback(). If both
// callbacks are null, there's nothing to do and the drop event is ignored.
virtual DropCallback GetDropCallback(const ui::DropTargetEvent& event) = 0;
virtual DropCallbackWithAnimation GetDropCallbackWithAnimation(
const ui::DropTargetEvent& event);

protected:
virtual ~DragDropDelegate() {}
Expand Down
5 changes: 5 additions & 0 deletions ui/views/view.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1877,6 +1877,11 @@ View::DropCallback View::GetDropCallback(const ui::DropTargetEvent& event) {
return base::NullCallback();
}

View::DropCallbackWithAnimation View::GetDropCallbackWithAnimation(
const ui::DropTargetEvent& event) {
return base::NullCallback();
}

// static
bool View::ExceededDragThreshold(const gfx::Vector2d& delta) {
return (abs(delta.x()) > GetHorizontalDragThreshold() ||
Expand Down
12 changes: 12 additions & 0 deletions ui/views/view.h
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ class ColorProvider;
class Compositor;
class InputMethod;
class Layer;
class LayerTreeOwner;
class NativeTheme;
class PaintContext;
class ThemeProvider;
Expand Down Expand Up @@ -295,6 +296,11 @@ class VIEWS_EXPORT View : public ui::LayerDelegate,
base::OnceCallback<void(const ui::DropTargetEvent& event,
ui::mojom::DragOperation& output_drag_op)>;

using DropCallbackWithAnimation = base::OnceCallback<void(
const ui::DropTargetEvent& event,
ui::mojom::DragOperation& output_drag_op,
std::unique_ptr<ui::LayerTreeOwner> old_layer_owner)>;

METADATA_HEADER_BASE(View);

enum class FocusBehavior {
Expand Down Expand Up @@ -1411,6 +1417,12 @@ class VIEWS_EXPORT View : public ui::LayerDelegate,
// uses View local coordinates.
virtual DropCallback GetDropCallback(const ui::DropTargetEvent& event);

// Invoked during a drag and drop session when the user release the mouse.
// Similar to GetDropCallback() but the returned callback has access to the
// drag image layer if any animation is needed.
virtual DropCallbackWithAnimation GetDropCallbackWithAnimation(
const ui::DropTargetEvent& event);

// Returns true if the mouse was dragged enough to start a drag operation.
// delta_x and y are the distance the mouse was dragged.
static bool ExceededDragThreshold(const gfx::Vector2d& delta);
Expand Down
46 changes: 46 additions & 0 deletions ui/views/widget/drop_helper.cc
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#include "build/build_config.h"
#include "ui/base/dragdrop/drag_drop_types.h"
#include "ui/base/dragdrop/mojom/drag_drop_types.mojom.h"
#include "ui/compositor/layer_tree_owner.h"
#include "ui/views/view.h"
#include "ui/views/widget/widget.h"

Expand Down Expand Up @@ -143,6 +144,51 @@ DropHelper::DropCallback DropHelper::GetDropCallback(
drop_event, std::move(drop_view_cb));
}

DropHelper::DropCallbackWithAnimation DropHelper::GetDropCallbackWithAnimation(
const OSExchangeData& data,
const gfx::Point& root_view_location,
int drag_operation) {
View* drop_view = target_view_;
if (!drop_view) {
return base::NullCallback();
}

if (drag_operation == ui::DragDropTypes::DRAG_NONE) {
drop_view->OnDragExited();
return base::NullCallback();
}

gfx::Point view_location(root_view_location);
View* root_view = drop_view->GetWidget()->GetRootView();
View::ConvertPointToTarget(root_view, drop_view, &view_location);
ui::DropTargetEvent drop_event(data, gfx::PointF(view_location),
gfx::PointF(view_location), drag_operation);

auto drop_view_cb = drop_view->GetDropCallbackWithAnimation(drop_event);
if (!drop_view_cb) {
return base::NullCallback();
}

// Only reset the target view when the helper successfully returns a callback.
// If no callback is returned here, GetDropCallback might still need the
// target view.
deepest_view_ = target_view_ = nullptr;

return base::BindOnce(
[](const ui::DropTargetEvent& drop_event,
View::DropCallbackWithAnimation drop_cb,
std::unique_ptr<ui::OSExchangeData> data,
ui::mojom::DragOperation& output_drag_op,
std::unique_ptr<ui::LayerTreeOwner> old_layer_owner) {
// Bind the drop_event here instead of using the one that the callback
// is invoked with as that event is in window coordinates and callbacks
// expect View coordinates.
std::move(drop_cb).Run(drop_event, output_drag_op,
std::move(old_layer_owner));
},
drop_event, std::move(drop_view_cb));
}

View* DropHelper::CalculateTargetView(const gfx::Point& root_view_location,
const OSExchangeData& data,
bool check_can_drop) {
Expand Down
16 changes: 16 additions & 0 deletions ui/views/widget/drop_helper.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,13 @@ class VIEWS_EXPORT DropHelper {
base::OnceCallback<void(std::unique_ptr<ui::OSExchangeData> data,
ui::mojom::DragOperation& output_drag_op)>;

// This is expected to match the signature of
// aura::client::DragDropDelegate::DropCallbackWithAnimation.
using DropCallbackWithAnimation = base::OnceCallback<void(
std::unique_ptr<ui::OSExchangeData> data,
ui::mojom::DragOperation& output_drag_op,
std::unique_ptr<ui::LayerTreeOwner> old_layer_owner)>;

explicit DropHelper(View* root_view);

DropHelper(const DropHelper&) = delete;
Expand Down Expand Up @@ -85,9 +92,18 @@ class VIEWS_EXPORT DropHelper {

// Invoked when the user drops data on the root view during a drag and drop
// operation, but the drop is held because of DataTransferPolicController.
// To fetch the correct callback, callers should invoke
// GetDropCallbackWithAnimation before GetDropCallback to potentially avoid
// clearing the |target_view_| in case GetDropCallback should need it.
DropCallback GetDropCallback(const OSExchangeData& data,
const gfx::Point& root_view_location,
int drag_operation);
DropCallbackWithAnimation GetDropCallbackWithAnimation(
const OSExchangeData& data,
const gfx::Point& root_view_location,
int drag_operation);

bool WillAnimateDragImageForDrop();

// Calculates the target view for a drop given the specified location in
// the coordinate system of the rootview. This tries to avoid continually
Expand Down
8 changes: 8 additions & 0 deletions ui/views/widget/native_widget_aura.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1199,6 +1199,14 @@ aura::client::DragDropDelegate::DropCallback NativeWidgetAura::GetDropCallback(
last_drop_operation_);
}

aura::client::DragDropDelegate::DropCallbackWithAnimation
NativeWidgetAura::GetDropCallbackWithAnimation(
const ui::DropTargetEvent& event) {
DCHECK(drop_helper_);
return drop_helper_->GetDropCallbackWithAnimation(
event.data(), event.location(), last_drop_operation_);
}

////////////////////////////////////////////////////////////////////////////////
// NativeWidgetAura, wm::TransientWindowObserver implementation:

Expand Down
2 changes: 2 additions & 0 deletions ui/views/widget/native_widget_aura.h
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,8 @@ class VIEWS_EXPORT NativeWidgetAura : public internal::NativeWidgetPrivate,
void OnDragExited() override;
aura::client::DragDropDelegate::DropCallback GetDropCallback(
const ui::DropTargetEvent& event) override;
aura::client::DragDropDelegate::DropCallbackWithAnimation
GetDropCallbackWithAnimation(const ui::DropTargetEvent& event) override;

// aura::TransientWindowObserver:
void OnTransientParentChanged(aura::Window* new_parent) override;
Expand Down

0 comments on commit 40d497c

Please sign in to comment.