Commit acbbf544 authored by Xiaodan Zhu's avatar Xiaodan Zhu Committed by Chromium LUCI CQ

Reorder virtual desks with drag and drop

This CL implements desks reordering with drag & drop. The main changes
are listed as below:

- Added response methods for mouse pressed, drag and released events in
  desk preview to trigger drag and drop.
- Added *DragDesk methods in desks bar view to handle drag and drop.
- Added a new class DeskDragProxy to create a proxy of desk being
  dragged.
- Added a method PerformMiniViewReorderAnimation to animate the
  movement of desks while reordering.

Bug: 1154038
Change-Id: I7633970a94d69e1326cf09eaede3929ca0acb811
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2602859
Commit-Queue: Ahmed Fakhry <afakhry@chromium.org>
Reviewed-by: default avatarAhmed Fakhry <afakhry@chromium.org>
Reviewed-by: default avatarSammie Quon <sammiequon@chromium.org>
Cr-Commit-Position: refs/heads/master@{#843858}
parent c2782790
...@@ -1496,6 +1496,8 @@ component("ash") { ...@@ -1496,6 +1496,8 @@ component("ash") {
"wm/desks/desk_animation_base.h", "wm/desks/desk_animation_base.h",
"wm/desks/desk_animation_impl.cc", "wm/desks/desk_animation_impl.cc",
"wm/desks/desk_animation_impl.h", "wm/desks/desk_animation_impl.h",
"wm/desks/desk_drag_proxy.cc",
"wm/desks/desk_drag_proxy.h",
"wm/desks/desk_mini_view.cc", "wm/desks/desk_mini_view.cc",
"wm/desks/desk_mini_view.h", "wm/desks/desk_mini_view.h",
"wm/desks/desk_mini_view_animations.cc", "wm/desks/desk_mini_view_animations.cc",
......
...@@ -251,6 +251,7 @@ class ASH_EXPORT ShelfLayoutManager ...@@ -251,6 +251,7 @@ class ASH_EXPORT ShelfLayoutManager
// DesksController::Observer: // DesksController::Observer:
void OnDeskAdded(const Desk* desk) override {} void OnDeskAdded(const Desk* desk) override {}
void OnDeskRemoved(const Desk* desk) override {} void OnDeskRemoved(const Desk* desk) override {}
void OnDeskReordered(int old_index, int new_index) override {}
void OnDeskActivationChanged(const Desk* activated, void OnDeskActivationChanged(const Desk* activated,
const Desk* deactivated) override {} const Desk* deactivated) override {}
void OnDeskSwitchAnimationLaunching() override; void OnDeskSwitchAnimationLaunching() override;
......
...@@ -39,6 +39,7 @@ class DeskAnimationObserver : public DesksController::Observer { ...@@ -39,6 +39,7 @@ class DeskAnimationObserver : public DesksController::Observer {
// DesksController::Observer: // DesksController::Observer:
void OnDeskAdded(const Desk* desk) override {} void OnDeskAdded(const Desk* desk) override {}
void OnDeskRemoved(const Desk* desk) override {} void OnDeskRemoved(const Desk* desk) override {}
void OnDeskReordered(int old_index, int new_index) override {}
void OnDeskActivationChanged(const Desk* activated, void OnDeskActivationChanged(const Desk* activated,
const Desk* deactivated) override {} const Desk* deactivated) override {}
void OnDeskSwitchAnimationLaunching() override {} void OnDeskSwitchAnimationLaunching() override {}
...@@ -102,6 +103,7 @@ class ChainedDeskAnimationObserver : public ui::LayerAnimationObserver, ...@@ -102,6 +103,7 @@ class ChainedDeskAnimationObserver : public ui::LayerAnimationObserver,
// DesksController::Observer: // DesksController::Observer:
void OnDeskAdded(const Desk* desk) override {} void OnDeskAdded(const Desk* desk) override {}
void OnDeskRemoved(const Desk* desk) override {} void OnDeskRemoved(const Desk* desk) override {}
void OnDeskReordered(int old_index, int new_index) override {}
void OnDeskActivationChanged(const Desk* activated, void OnDeskActivationChanged(const Desk* activated,
const Desk* deactivated) override { const Desk* deactivated) override {
// The first activation changed happens when the initial ending screenshot // The first activation changed happens when the initial ending screenshot
......
...@@ -32,6 +32,7 @@ class TestDesksActivationObserver : public DesksController::Observer { ...@@ -32,6 +32,7 @@ class TestDesksActivationObserver : public DesksController::Observer {
// DesksController::Observer: // DesksController::Observer:
void OnDeskAdded(const Desk* desk) override {} void OnDeskAdded(const Desk* desk) override {}
void OnDeskRemoved(const Desk* desk) override {} void OnDeskRemoved(const Desk* desk) override {}
void OnDeskReordered(int old_index, int new_index) override {}
void OnDeskActivationChanged(const Desk* activated, void OnDeskActivationChanged(const Desk* activated,
const Desk* deactivated) override { const Desk* deactivated) override {
++activation_changes_; ++activation_changes_;
......
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ash/wm/desks/desk_drag_proxy.h"
#include "ash/drag_drop/drag_image_view.h"
#include "ash/wm/desks/desk_mini_view.h"
#include "ash/wm/desks/desk_preview_view.h"
#include "ash/wm/desks/desks_bar_view.h"
#include "ui/base/dragdrop/mojom/drag_drop_types.mojom-shared.h"
#include "ui/compositor/scoped_layer_animation_settings.h"
#include "ui/display/screen.h"
#include "ui/events/event_observer.h"
#include "ui/gfx/transform_util.h"
#include "ui/views/widget/widget.h"
namespace ash {
namespace {
// Scale of dragged desk proxy.
constexpr float kDragProxyScale = 1.2f;
// Time duration of scaling up dragged desk proxy.
constexpr base::TimeDelta kDragProxyScaleUpDuration =
base::TimeDelta::FromMilliseconds(200);
// Time duration of snapping back drag proxy.
constexpr base::TimeDelta kDragProxySnapBackDuration =
base::TimeDelta::FromMilliseconds(300);
} // namespace
DeskDragProxy::DeskDragProxy(DesksBarView* desks_bar_view,
DeskMiniView* drag_view,
const gfx::Vector2dF& init_offset)
: desks_bar_view_(desks_bar_view),
drag_view_(drag_view),
drag_preview_size_(drag_view->GetPreviewBoundsInScreen().size()),
init_offset_(init_offset) {
DCHECK(drag_view_);
aura::Window* root_window =
drag_view_->GetWidget()->GetNativeWindow()->GetRootWindow();
// Create a drag widget.
drag_widget_ =
DragImageView::Create(root_window, ui::mojom::DragEventSource::kMouse);
// Turn off the fade animation.
drag_widget_->SetVisibilityAnimationTransition(views::Widget::ANIMATE_NONE);
// Copy the preview of the dragged desk to the widget content.
drag_widget_->SetContentsView(std::make_unique<DeskPreviewView>(
views::Button::PressedCallback(), drag_view_));
// Set the bounds of dragged preview to drag proxy.
drag_widget_->SetBounds(drag_view_->GetPreviewBoundsInScreen());
drag_widget_->Show();
}
void DeskDragProxy::OnImplicitAnimationsCompleted() {
DCHECK(desks_bar_view_);
desks_bar_view_->FinalizeDragDesk();
}
gfx::Point DeskDragProxy::GetPositionInScreen() const {
return drag_widget_->GetWindowBoundsInScreen().origin();
}
void DeskDragProxy::ScaleAndMoveTo(const gfx::PointF& location_in_screen) {
ui::Layer* layer = drag_widget_->GetLayer();
// Perform and animate scaling.
gfx::Transform scale_transform;
scale_transform.Scale(kDragProxyScale, kDragProxyScale);
ui::ScopedLayerAnimationSettings settings(layer->GetAnimator());
settings.SetTransitionDuration(kDragProxyScaleUpDuration);
// Scale the bounds around its center.
gfx::Rect proxy_bounds_in_screen = drag_widget_->GetWindowBoundsInScreen();
layer->SetTransform(gfx::TransformAboutPivot(
proxy_bounds_in_screen.CenterPoint() -
proxy_bounds_in_screen.origin().OffsetFromOrigin(),
scale_transform));
// Perform Moving.
DragTo(location_in_screen);
}
void DeskDragProxy::DragTo(const gfx::PointF& location_in_screen) {
drag_widget_->SetBounds(
gfx::Rect(gfx::ToRoundedPoint(location_in_screen - init_offset_),
drag_preview_size_));
}
void DeskDragProxy::SnapBackToDragView() {
ui::Layer* layer = drag_widget_->GetLayer();
// Cache proxy's bounds and drag view's bounds.
gfx::RectF scaled_proxy_bounds(drag_widget_->GetWindowBoundsInScreen());
scaled_proxy_bounds.set_size(
gfx::ScaleSize(scaled_proxy_bounds.size(), kDragProxyScale));
const gfx::Rect drag_view_bounds = drag_view_->GetPreviewBoundsInScreen();
// Set bounds of drag view to drag proxy.
drag_widget_->SetBounds(drag_view_bounds);
// Animate snapping back.
layer->SetTransform(gfx::TransformBetweenRects(gfx::RectF(drag_view_bounds),
scaled_proxy_bounds));
ui::ScopedLayerAnimationSettings settings(layer->GetAnimator());
settings.SetTransitionDuration(kDragProxySnapBackDuration);
settings.AddObserver(this);
layer->SetTransform(gfx::Transform());
}
} // namespace ash
// Copyright 2021 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef ASH_WM_DESKS_DESK_DRAG_PROXY_H_
#define ASH_WM_DESKS_DESK_DRAG_PROXY_H_
#include "ui/compositor/layer_animation_observer.h"
#include "ui/views/widget/unique_widget_ptr.h"
namespace views {
class View;
} // namespace views
namespace aura {
class Window;
} // namespace aura
namespace ash {
class DeskMiniView;
class DeskPreviewView;
class DesksBarView;
// A helper class includes a widget whose content is the preview of the dragged
// desk.
// TODO(zxdan): Consider adding a DeskDragController to handle the communication
// between DeskPreviewView and DesksBarView after M89.
class DeskDragProxy : public ui::ImplicitAnimationObserver {
public:
DeskDragProxy(DesksBarView* desks_bar_view,
DeskMiniView* drag_view,
const gfx::Vector2dF& init_offset);
DeskDragProxy(const DeskDragProxy&) = delete;
DeskDragProxy& operator=(const DeskDragProxy&) = delete;
~DeskDragProxy() override = default;
// ui::ImplicitAnimationObserver:
void OnImplicitAnimationsCompleted() override;
gfx::Point GetPositionInScreen() const;
// Perform and animate scaling up of drag proxy. Move drag proxy to
// |location_in_screen|.
void ScaleAndMoveTo(const gfx::PointF& location_in_screen);
// Move drag proxy to |location_in_screen|.
void DragTo(const gfx::PointF& location_in_screen);
// Perform and animate snapping back to drag view.
void SnapBackToDragView();
private:
DesksBarView* desks_bar_view_ = nullptr;
// The desk's mini view being dragged.
DeskMiniView* drag_view_ = nullptr;
// The size of dragged preview.
const gfx::Size drag_preview_size_;
// The initial offset between cursor and drag view's origin.
gfx::Vector2dF init_offset_;
// The widget of drag proxy.
views::UniqueWidgetPtr drag_widget_;
};
} // namespace ash
#endif // ASH_WM_DESKS_DESK_DRAG_PROXY_H_
...@@ -95,6 +95,11 @@ DeskMiniView::~DeskMiniView() { ...@@ -95,6 +95,11 @@ DeskMiniView::~DeskMiniView() {
desk_->RemoveObserver(this); desk_->RemoveObserver(this);
} }
gfx::Rect DeskMiniView::GetPreviewBoundsInScreen() const {
DCHECK(desk_preview_);
return desk_preview_->GetBoundsInScreen();
}
aura::Window* DeskMiniView::GetDeskContainer() const { aura::Window* DeskMiniView::GetDeskContainer() const {
DCHECK(desk_); DCHECK(desk_);
return desk_->GetDeskContainerForRoot(root_window_); return desk_->GetDeskContainerForRoot(root_window_);
...@@ -111,7 +116,7 @@ void DeskMiniView::UpdateCloseButtonVisibility() { ...@@ -111,7 +116,7 @@ void DeskMiniView::UpdateCloseButtonVisibility() {
// navigate to it. // navigate to it.
close_desk_button_->SetVisible( close_desk_button_->SetVisible(
DesksController::Get()->CanRemoveDesks() && DesksController::Get()->CanRemoveDesks() &&
!owner_bar_->dragged_item_over_bar() && !owner_bar_->dragged_item_over_bar() && !owner_bar_->IsDraggingDesk() &&
(IsMouseHovered() || force_show_close_button_ || (IsMouseHovered() || force_show_close_button_ ||
Shell::Get()->accessibility_controller()->IsSwitchAccessRunning())); Shell::Get()->accessibility_controller()->IsSwitchAccessRunning()));
} }
......
...@@ -47,6 +47,10 @@ class ASH_EXPORT DeskMiniView ...@@ -47,6 +47,10 @@ class ASH_EXPORT DeskMiniView
return close_desk_button_; return close_desk_button_;
} }
DesksBarView* owner_bar() { return owner_bar_; }
gfx::Rect GetPreviewBoundsInScreen() const;
// Returns the associated desk's container window on the display this // Returns the associated desk's container window on the display this
// mini_view resides on. // mini_view resides on.
aura::Window* GetDeskContainer() const; aura::Window* GetDeskContainer() const;
......
...@@ -274,4 +274,38 @@ void PerformExpandedStateToZeroStateMiniViewAnimation( ...@@ -274,4 +274,38 @@ void PerformExpandedStateToZeroStateMiniViewAnimation(
PositionWindowsInOverview(); PositionWindowsInOverview();
} }
void PerformReorderDeskMiniViewAnimation(
int old_index,
int new_index,
const std::vector<DeskMiniView*>& mini_views) {
const int views_size = static_cast<int>(mini_views.size());
DCHECK_GE(old_index, 0);
DCHECK_LT(old_index, views_size);
DCHECK_GE(new_index, 0);
DCHECK_LT(new_index, views_size);
if (old_index == new_index)
return;
// Reordering should be finished before calling this function. The source view
// and the target view has been exchanged. The range should be selected
// according to current mini views position.
const int start_index = old_index < new_index ? old_index : new_index + 1;
const int end_index = old_index < new_index ? new_index : old_index + 1;
// Since |old_index| and |new_index| are unequal valid indices, there
// must be at least two desks.
int shift_x = mini_views[0]->bounds().origin().x() -
mini_views[1]->bounds().origin().x();
shift_x = old_index < new_index ? -shift_x : shift_x;
gfx::Transform desks_transform;
desks_transform.Translate(shift_x, 0);
auto start_iter = mini_views.begin();
AnimateMiniViews(std::vector<DeskMiniView*>(start_iter + start_index,
start_iter + end_index),
desks_transform);
}
} // namespace ash } // namespace ash
...@@ -77,6 +77,22 @@ void PerformExpandedStateToZeroStateMiniViewAnimation( ...@@ -77,6 +77,22 @@ void PerformExpandedStateToZeroStateMiniViewAnimation(
DesksBarView* bar_view, DesksBarView* bar_view,
std::vector<DeskMiniView*> removed_mini_views); std::vector<DeskMiniView*> removed_mini_views);
// Performs the mini_view reorder animation. It moves the desks to make space at
// |new_index| for the mini_view at |old_index|. Before reordering, if
// |old_index| < |new_index|, the mini views from |old_index| + 1 to
// |new_index| would move left; if |old_index| > |new_index|, the mini
// views from |new_index| to |old_index| - 1 would move right.
//
// Note that the |mini_views| is the reordered list. Therefore, the range of the
// mini views to be moved should be selected according to the current position.
// If |old_index| < |new_index|, the range is from |old_index| to
// |new_index| - 1; otherwise, the range is from |new_index| + 1 to
// |old_index|.
void PerformReorderDeskMiniViewAnimation(
int old_index,
int new_index,
const std::vector<DeskMiniView*>& mini_views);
} // namespace ash } // namespace ash
#endif // ASH_WM_DESKS_DESK_MINI_VIEW_ANIMATIONS_H_ #endif // ASH_WM_DESKS_DESK_MINI_VIEW_ANIMATIONS_H_
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#include "ash/shell.h" #include "ash/shell.h"
#include "ash/wallpaper/wallpaper_base_view.h" #include "ash/wallpaper/wallpaper_base_view.h"
#include "ash/wm/desks/desk_mini_view.h" #include "ash/wm/desks/desk_mini_view.h"
#include "ash/wm/desks/desks_bar_view.h"
#include "ash/wm/desks/desks_controller.h" #include "ash/wm/desks/desks_controller.h"
#include "ash/wm/desks/desks_util.h" #include "ash/wm/desks/desks_util.h"
#include "ash/wm/mru_window_tracker.h" #include "ash/wm/mru_window_tracker.h"
...@@ -413,4 +414,57 @@ void DeskPreviewView::Layout() { ...@@ -413,4 +414,57 @@ void DeskPreviewView::Layout() {
Button::Layout(); Button::Layout();
} }
bool DeskPreviewView::OnMouseDragged(const ui::MouseEvent& event) {
if (!features::IsBentoEnabled())
return Button::OnMouseDragged(event);
DesksBarView* owner_bar = mini_view_->owner_bar();
if (!owner_bar->IsDraggingDesk()) {
owner_bar->HandleStartDragEvent(mini_view_, event);
return true;
}
if (!owner_bar->HandleDragEvent(mini_view_, event))
return Button::OnMouseDragged(event);
return true;
}
void DeskPreviewView::OnMouseReleased(const ui::MouseEvent& event) {
if (!mini_view_->owner_bar()->HandleReleaseEvent(mini_view_, event))
Button::OnMouseReleased(event);
}
void DeskPreviewView::OnGestureEvent(ui::GestureEvent* event) {
if (!features::IsBentoEnabled()) {
Button::OnGestureEvent(event);
return;
}
DesksBarView* owner_bar = mini_view_->owner_bar();
switch (event->type()) {
case ui::ET_GESTURE_LONG_PRESS:
owner_bar->HandleStartDragEvent(mini_view_, *event);
event->SetHandled();
break;
case ui::ET_GESTURE_SCROLL_BEGIN:
FALLTHROUGH;
case ui::ET_GESTURE_SCROLL_UPDATE:
if (owner_bar->HandleDragEvent(mini_view_, *event))
event->SetHandled();
break;
case ui::ET_GESTURE_END:
if (owner_bar->HandleReleaseEvent(mini_view_, *event))
event->SetHandled();
break;
default:
break;
}
if (!event->handled())
Button::OnGestureEvent(event);
}
} // namespace ash } // namespace ash
...@@ -82,6 +82,9 @@ class ASH_EXPORT DeskPreviewView : public views::Button { ...@@ -82,6 +82,9 @@ class ASH_EXPORT DeskPreviewView : public views::Button {
// views::View: // views::View:
const char* GetClassName() const override; const char* GetClassName() const override;
void Layout() override; void Layout() override;
bool OnMouseDragged(const ui::MouseEvent& event) override;
void OnMouseReleased(const ui::MouseEvent& event) override;
void OnGestureEvent(ui::GestureEvent* event) override;
private: private:
class ShadowRenderer; class ShadowRenderer;
......
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#include "ash/public/cpp/window_properties.h" #include "ash/public/cpp/window_properties.h"
#include "ash/shell.h" #include "ash/shell.h"
#include "ash/style/ash_color_provider.h" #include "ash/style/ash_color_provider.h"
#include "ash/wm/desks/desk_drag_proxy.h"
#include "ash/wm/desks/desk_mini_view.h" #include "ash/wm/desks/desk_mini_view.h"
#include "ash/wm/desks/desk_mini_view_animations.h" #include "ash/wm/desks/desk_mini_view_animations.h"
#include "ash/wm/desks/desk_name_view.h" #include "ash/wm/desks/desk_name_view.h"
...@@ -33,7 +34,9 @@ ...@@ -33,7 +34,9 @@
#include "ui/views/controls/scroll_view.h" #include "ui/views/controls/scroll_view.h"
#include "ui/views/event_monitor.h" #include "ui/views/event_monitor.h"
#include "ui/views/layout/fill_layout.h" #include "ui/views/layout/fill_layout.h"
#include "ui/views/widget/unique_widget_ptr.h"
#include "ui/views/widget/widget.h" #include "ui/views/widget/widget.h"
#include "ui/wm/core/cursor_manager.h"
#include "ui/wm/core/window_animations.h" #include "ui/wm/core/window_animations.h"
namespace ash { namespace ash {
...@@ -77,6 +80,31 @@ OverviewHighlightController* GetHighlightController() { ...@@ -77,6 +80,31 @@ OverviewHighlightController* GetHighlightController() {
return overview_controller->overview_session()->highlight_controller(); return overview_controller->overview_session()->highlight_controller();
} }
int DetermineMoveIndex(const std::vector<DeskMiniView*>& views,
int old_index,
int location_screen_x) {
DCHECK_GE(old_index, 0);
const int views_size = static_cast<int>(views.size());
DCHECK_LT(old_index, views_size);
for (int new_index = 0; new_index < views_size; new_index++) {
// Note that we cannot directly use |GetBoundsInScreen|. Because we may
// perform animation (transform) on mini views. The bounds gotten from
// |GetBoundsInScreen| may be the intermediate bounds during animation.
// Therefore, we transfer a mini view's origin from its parent level to
// avoid the influence of its own transform.
auto* view = views[new_index];
gfx::Point center_in_screen = view->bounds().CenterPoint();
views::View::ConvertPointToScreen(view->parent(), &center_in_screen);
if (location_screen_x < center_in_screen.x())
return new_index;
}
return views_size - 1;
}
} // namespace } // namespace
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
...@@ -331,6 +359,8 @@ DesksBarView::DesksBarView(OverviewGrid* overview_grid) ...@@ -331,6 +359,8 @@ DesksBarView::DesksBarView(OverviewGrid* overview_grid)
DesksBarView::~DesksBarView() { DesksBarView::~DesksBarView() {
DesksController::Get()->RemoveObserver(this); DesksController::Get()->RemoveObserver(this);
if (drag_view_)
EndDragDesk(drag_view_, /*end_by_user=*/false);
} }
// static // static
...@@ -433,6 +463,108 @@ bool DesksBarView::IsZeroState() const { ...@@ -433,6 +463,108 @@ bool DesksBarView::IsZeroState() const {
DesksController::Get()->desks().size() == 1; DesksController::Get()->desks().size() == 1;
} }
void DesksBarView::HandleStartDragEvent(DeskMiniView* mini_view,
const ui::LocatedEvent& event) {
DeskNameView::CommitChanges(GetWidget());
gfx::PointF location = event.target()->GetScreenLocationF(event);
StartDragDesk(mini_view, location);
}
bool DesksBarView::HandleDragEvent(DeskMiniView* mini_view,
const ui::LocatedEvent& event) {
gfx::PointF location = event.target()->GetScreenLocationF(event);
return ContinueDragDesk(mini_view, location);
}
bool DesksBarView::HandleReleaseEvent(DeskMiniView* mini_view,
const ui::LocatedEvent& event) {
return EndDragDesk(mini_view, /*end_by_user=*/true);
}
void DesksBarView::StartDragDesk(DeskMiniView* mini_view,
const gfx::PointF& location_in_screen) {
// If another view is being dragged, then end the drag.
if (drag_view_)
EndDragDesk(drag_view_, /*end_by_user=*/false);
drag_view_ = mini_view;
gfx::PointF preview_origin_in_screen(
drag_view_->GetPreviewBoundsInScreen().origin());
gfx::Vector2dF drag_origin_offset =
location_in_screen - preview_origin_in_screen;
// Hide the dragged mini view.
drag_view_->layer()->SetOpacity(0.0f);
// Create a drag proxy for the dragged desk.
drag_proxy_ =
std::make_unique<DeskDragProxy>(this, drag_view_, drag_origin_offset);
drag_proxy_->ScaleAndMoveTo(location_in_screen);
Shell::Get()->cursor_manager()->SetCursor(ui::mojom::CursorType::kGrabbing);
}
bool DesksBarView::ContinueDragDesk(DeskMiniView* mini_view,
const gfx::PointF& location_in_screen) {
if (!drag_view_ || mini_view != drag_view_)
return false;
drag_proxy_->DragTo(location_in_screen);
const auto drag_view_iter =
std::find(mini_views_.cbegin(), mini_views_.cend(), drag_view_);
DCHECK(drag_view_iter != mini_views_.cend());
int old_index = drag_view_iter - mini_views_.cbegin();
gfx::Point drag_pos_in_screen = drag_proxy_->GetPositionInScreen();
gfx::Rect bar_bounds = scroll_view_contents_->GetBoundsInScreen();
float cursor_y = location_in_screen.y();
// Determine the target location for the desk to be reordered. If the cursor
// is outside the desks bar, then the dragged desk will be moved to the end.
// Otherwise, the position is determined by the drag proxy's location.
int new_index =
(cursor_y < bar_bounds.origin().y() || cursor_y > bar_bounds.bottom())
? mini_views_.size() - 1
: DetermineMoveIndex(mini_views_, old_index, drag_pos_in_screen.x());
Shell::Get()->desks_controller()->ReorderDesk(old_index, new_index);
return true;
}
bool DesksBarView::EndDragDesk(DeskMiniView* mini_view, bool end_by_user) {
if (!drag_view_ || mini_view != drag_view_)
return false;
// Update default desk names after dropping.
Shell::Get()->desks_controller()->UpdateDesksDefaultNames();
Shell::Get()->cursor_manager()->SetCursor(ui::mojom::CursorType::kPointer);
// If the reordering is ended by the user (release the drag), perform the
// snapping back animation. Otherwise, directly finalize the drag.
if (end_by_user)
drag_proxy_->SnapBackToDragView();
else
FinalizeDragDesk();
return true;
}
void DesksBarView::FinalizeDragDesk() {
if (drag_view_) {
drag_view_->layer()->SetOpacity(1.0f);
drag_view_ = nullptr;
}
drag_proxy_.reset();
}
bool DesksBarView::IsDraggingDesk() const {
return drag_view_ != nullptr;
}
const char* DesksBarView::GetClassName() const { const char* DesksBarView::GetClassName() const {
return "DesksBarView"; return "DesksBarView";
} }
...@@ -532,6 +664,15 @@ void DesksBarView::OnDeskRemoved(const Desk* desk) { ...@@ -532,6 +664,15 @@ void DesksBarView::OnDeskRemoved(const Desk* desk) {
expanded_state_new_desk_button_, begin_x - GetFirstMiniViewXOffset()); expanded_state_new_desk_button_, begin_x - GetFirstMiniViewXOffset());
} }
void DesksBarView::OnDeskReordered(int old_index, int new_index) {
desks_util::ReorderItem(mini_views_, old_index, new_index);
overview_grid_->OnDesksChanged();
// Call the animation function after reorder the mini views.
PerformReorderDeskMiniViewAnimation(old_index, new_index, mini_views_);
}
void DesksBarView::OnDeskActivationChanged(const Desk* activated, void DesksBarView::OnDeskActivationChanged(const Desk* activated,
const Desk* deactivated) { const Desk* deactivated) {
for (auto* mini_view : mini_views_) { for (auto* mini_view : mini_views_) {
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
namespace ash { namespace ash {
class DeskBarHoverObserver; class DeskBarHoverObserver;
class DeskDragProxy;
class DeskMiniView; class DeskMiniView;
class ExpandedStateNewDeskButton; class ExpandedStateNewDeskButton;
class NewDeskButton; class NewDeskButton;
...@@ -103,6 +104,29 @@ class ASH_EXPORT DesksBarView : public views::View, ...@@ -103,6 +104,29 @@ class ASH_EXPORT DesksBarView : public views::View,
// there's only a single desk available, in which case the bar is shown in a // there's only a single desk available, in which case the bar is shown in a
// minimized state. // minimized state.
bool IsZeroState() const; bool IsZeroState() const;
// Handle drag & drop events for each desk preview.
void HandleStartDragEvent(DeskMiniView* mini_view,
const ui::LocatedEvent& event);
// Return true if the drag event is handled by drag & drop.
bool HandleDragEvent(DeskMiniView* mini_view, const ui::LocatedEvent& event);
// Return true if the release event is handled by drag & drop.
bool HandleReleaseEvent(DeskMiniView* mini_view,
const ui::LocatedEvent& event);
// Trigger drag & drop. Create a proxy for the dragged desk.
void StartDragDesk(DeskMiniView* mini_view,
const gfx::PointF& location_in_screen);
// Reorder desks according to the drag proxy's location. Return true if the
// dragged desk is reordered.
bool ContinueDragDesk(DeskMiniView* mini_view,
const gfx::PointF& location_in_screen);
// Snap back the drag proxy to the drag view's location. Return true if
// current drag is ended.
bool EndDragDesk(DeskMiniView* mini_view, bool end_by_user);
// Reset the drag view and the drag proxy.
void FinalizeDragDesk();
// If a desk is in a drag & drop cycle.
bool IsDraggingDesk() const;
// views::View: // views::View:
const char* GetClassName() const override; const char* GetClassName() const override;
...@@ -119,6 +143,7 @@ class ASH_EXPORT DesksBarView : public views::View, ...@@ -119,6 +143,7 @@ class ASH_EXPORT DesksBarView : public views::View,
// DesksController::Observer: // DesksController::Observer:
void OnDeskAdded(const Desk* desk) override; void OnDeskAdded(const Desk* desk) override;
void OnDeskRemoved(const Desk* desk) override; void OnDeskRemoved(const Desk* desk) override;
void OnDeskReordered(int old_index, int new_index) override;
void OnDeskActivationChanged(const Desk* activated, void OnDeskActivationChanged(const Desk* activated,
const Desk* deactivated) override; const Desk* deactivated) override;
void OnDeskSwitchAnimationLaunching() override; void OnDeskSwitchAnimationLaunching() override;
...@@ -195,6 +220,10 @@ class ASH_EXPORT DesksBarView : public views::View, ...@@ -195,6 +220,10 @@ class ASH_EXPORT DesksBarView : public views::View,
ZeroStateDefaultDeskButton* zero_state_default_desk_button_; ZeroStateDefaultDeskButton* zero_state_default_desk_button_;
ZeroStateNewDeskButton* zero_state_new_desk_button_; ZeroStateNewDeskButton* zero_state_new_desk_button_;
ExpandedStateNewDeskButton* expanded_state_new_desk_button_; ExpandedStateNewDeskButton* expanded_state_new_desk_button_;
// Mini view whose preview is being dragged.
DeskMiniView* drag_view_ = nullptr;
// Drag proxy for the dragged desk.
std::unique_ptr<DeskDragProxy> drag_proxy_;
DISALLOW_COPY_AND_ASSIGN(DesksBarView); DISALLOW_COPY_AND_ASSIGN(DesksBarView);
}; };
......
...@@ -378,6 +378,13 @@ void DesksController::RemoveDesk(const Desk* desk, ...@@ -378,6 +378,13 @@ void DesksController::RemoveDesk(const Desk* desk,
RemoveDeskInternal(desk, source); RemoveDeskInternal(desk, source);
} }
void DesksController::ReorderDesk(int old_index, int new_index) {
desks_util::ReorderItem(desks_, old_index, new_index);
for (auto& observer : observers_)
observer.OnDeskReordered(old_index, new_index);
}
void DesksController::ActivateDesk(const Desk* desk, DesksSwitchSource source) { void DesksController::ActivateDesk(const Desk* desk, DesksSwitchSource source) {
DCHECK(HasDesk(desk)); DCHECK(HasDesk(desk));
DCHECK(!animation_); DCHECK(!animation_);
...@@ -634,6 +641,16 @@ void DesksController::SendToDeskAtIndex(aura::Window* window, int desk_index) { ...@@ -634,6 +641,16 @@ void DesksController::SendToDeskAtIndex(aura::Window* window, int desk_index) {
DesksMoveWindowFromActiveDeskSource::kSendToDesk); DesksMoveWindowFromActiveDeskSource::kSendToDesk);
} }
void DesksController::UpdateDesksDefaultNames() {
size_t i = 0;
for (auto& desk : desks_) {
// Do not overwrite user-modified desks' names.
if (!desk->is_name_set_by_user())
desk->SetName(GetDeskDefaultName(i), /*set_by_user=*/false);
i++;
}
}
void DesksController::OnWindowActivating(ActivationReason reason, void DesksController::OnWindowActivating(ActivationReason reason,
aura::Window* gaining_active, aura::Window* gaining_active,
aura::Window* losing_active) { aura::Window* losing_active) {
...@@ -1024,14 +1041,4 @@ void DesksController::ReportDesksCountHistogram() const { ...@@ -1024,14 +1041,4 @@ void DesksController::ReportDesksCountHistogram() const {
desks_util::GetMaxNumberOfDesks()); desks_util::GetMaxNumberOfDesks());
} }
void DesksController::UpdateDesksDefaultNames() {
size_t i = 0;
for (auto& desk : desks_) {
// Do not overwrite user-modified desks' names.
if (!desk->is_name_set_by_user())
desk->SetName(GetDeskDefaultName(i), /*set_by_user=*/false);
i++;
}
}
} // namespace ash } // namespace ash
...@@ -48,6 +48,9 @@ class ASH_EXPORT DesksController : public DesksHelper, ...@@ -48,6 +48,9 @@ class ASH_EXPORT DesksController : public DesksHelper,
// observers have been notified with this. // observers have been notified with this.
virtual void OnDeskRemoved(const Desk* desk) = 0; virtual void OnDeskRemoved(const Desk* desk) = 0;
// Called when the desk at |old_index| is reordered to |new_index|.
virtual void OnDeskReordered(int old_index, int new_index) = 0;
// Called when the |activated| desk gains activation from the |deactivated| // Called when the |activated| desk gains activation from the |deactivated|
// desk. // desk.
virtual void OnDeskActivationChanged(const Desk* activated, virtual void OnDeskActivationChanged(const Desk* activated,
...@@ -123,6 +126,9 @@ class ASH_EXPORT DesksController : public DesksHelper, ...@@ -123,6 +126,9 @@ class ASH_EXPORT DesksController : public DesksHelper,
// removed outside of overview. // removed outside of overview.
void RemoveDesk(const Desk* desk, DesksCreationRemovalSource source); void RemoveDesk(const Desk* desk, DesksCreationRemovalSource source);
// Reorder the desk at |old_index| to |new_index|.
void ReorderDesk(int old_index, int new_index);
// Performs the desk switch animation on all root windows to activate the // Performs the desk switch animation on all root windows to activate the
// given |desk| and to deactivate the currently active one. |desk| has to be // given |desk| and to deactivate the currently active one. |desk| has to be
// an existing desk. The active window on the currently active desk will be // an existing desk. The active window on the currently active desk will be
...@@ -195,6 +201,11 @@ class ASH_EXPORT DesksController : public DesksHelper, ...@@ -195,6 +201,11 @@ class ASH_EXPORT DesksController : public DesksHelper,
int GetNumberOfDesks() const override; int GetNumberOfDesks() const override;
void SendToDeskAtIndex(aura::Window* window, int desk_index) override; void SendToDeskAtIndex(aura::Window* window, int desk_index) override;
// Updates the default names (e.g. "Desk 1", "Desk 2", ... etc.) given to the
// desks. This is called when desks are added, removed or reordered to update
// the names based on the desks order.
void UpdateDesksDefaultNames();
// ::wm::ActivationChangeObserver: // ::wm::ActivationChangeObserver:
void OnWindowActivating(ActivationReason reason, void OnWindowActivating(ActivationReason reason,
aura::Window* gaining_active, aura::Window* gaining_active,
...@@ -250,11 +261,6 @@ class ASH_EXPORT DesksController : public DesksHelper, ...@@ -250,11 +261,6 @@ class ASH_EXPORT DesksController : public DesksHelper,
void ReportDesksCountHistogram() const; void ReportDesksCountHistogram() const;
// Updates the default names (e.g. "Desk 1", "Desk 2", ... etc.) given to the
// desks. This is called when desks are added or removed to update the names
// based on the desks order.
void UpdateDesksDefaultNames();
std::vector<std::unique_ptr<Desk>> desks_; std::vector<std::unique_ptr<Desk>> desks_;
Desk* active_desk_ = nullptr; Desk* active_desk_ = nullptr;
......
...@@ -30,6 +30,8 @@ void DeskSwitchAnimationWaiter::OnDeskAdded(const Desk* desk) {} ...@@ -30,6 +30,8 @@ void DeskSwitchAnimationWaiter::OnDeskAdded(const Desk* desk) {}
void DeskSwitchAnimationWaiter::OnDeskRemoved(const Desk* desk) {} void DeskSwitchAnimationWaiter::OnDeskRemoved(const Desk* desk) {}
void DeskSwitchAnimationWaiter::OnDeskReordered(int old_index, int new_index) {}
void DeskSwitchAnimationWaiter::OnDeskActivationChanged( void DeskSwitchAnimationWaiter::OnDeskActivationChanged(
const Desk* activated, const Desk* activated,
const Desk* deactivated) {} const Desk* deactivated) {}
......
...@@ -23,6 +23,7 @@ class DeskSwitchAnimationWaiter : public DesksController::Observer { ...@@ -23,6 +23,7 @@ class DeskSwitchAnimationWaiter : public DesksController::Observer {
// DesksController::Observer: // DesksController::Observer:
void OnDeskAdded(const Desk* desk) override; void OnDeskAdded(const Desk* desk) override;
void OnDeskRemoved(const Desk* desk) override; void OnDeskRemoved(const Desk* desk) override;
void OnDeskReordered(int old_index, int new_index) override;
void OnDeskActivationChanged(const Desk* activated, void OnDeskActivationChanged(const Desk* activated,
const Desk* deactivated) override; const Desk* deactivated) override;
void OnDeskSwitchAnimationLaunching() override; void OnDeskSwitchAnimationLaunching() override;
......
...@@ -277,6 +277,7 @@ class TestObserver : public DesksController::Observer { ...@@ -277,6 +277,7 @@ class TestObserver : public DesksController::Observer {
base::Erase(desks_, desk); base::Erase(desks_, desk);
EXPECT_TRUE(DesksController::Get()->AreDesksBeingModified()); EXPECT_TRUE(DesksController::Get()->AreDesksBeingModified());
} }
void OnDeskReordered(int old_index, int new_index) override {}
void OnDeskActivationChanged(const Desk* activated, void OnDeskActivationChanged(const Desk* activated,
const Desk* deactivated) override { const Desk* deactivated) override {
EXPECT_TRUE(DesksController::Get()->AreDesksBeingModified()); EXPECT_TRUE(DesksController::Get()->AreDesksBeingModified());
......
...@@ -5,10 +5,12 @@ ...@@ -5,10 +5,12 @@
#ifndef ASH_WM_DESKS_DESKS_UTIL_H_ #ifndef ASH_WM_DESKS_DESKS_UTIL_H_
#define ASH_WM_DESKS_DESKS_UTIL_H_ #define ASH_WM_DESKS_DESKS_UTIL_H_
#include <algorithm>
#include <vector> #include <vector>
#include "ash/ash_export.h" #include "ash/ash_export.h"
#include "ash/public/cpp/shell_window_ids.h" #include "ash/public/cpp/shell_window_ids.h"
#include "base/check_op.h"
#include "ui/compositor/compositor.h" #include "ui/compositor/compositor.h"
namespace aura { namespace aura {
...@@ -58,6 +60,30 @@ ASH_EXPORT bool ShouldDesksBarBeCreated(); ...@@ -58,6 +60,30 @@ ASH_EXPORT bool ShouldDesksBarBeCreated();
// Selects and returns the compositor to measure performance metrics. // Selects and returns the compositor to measure performance metrics.
ui::Compositor* GetSelectedCompositorForPerformanceMetrics(); ui::Compositor* GetSelectedCompositorForPerformanceMetrics();
// Move an item at |old_index| to |new_index|.
template <typename T>
ASH_EXPORT void ReorderItem(std::vector<T>& items,
int old_index,
int new_index) {
const int items_size = static_cast<int>(items.size());
DCHECK_GE(old_index, 0);
DCHECK_LT(old_index, items_size);
DCHECK_GE(new_index, 0);
DCHECK_LT(new_index, items_size);
if (old_index == new_index)
return;
auto start_iter = items.begin();
const int step = old_index < new_index ? 1 : -1;
for (auto iter = start_iter + old_index; iter != start_iter + new_index;
iter += step) {
std::iter_swap(iter, iter + step);
}
}
} // namespace desks_util } // namespace desks_util
} // namespace ash } // namespace ash
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment