Skip to content

Commit

Permalink
cros_next: Implement drag and drop window in overview for Jellyroll
Browse files Browse the repository at this point in the history
When dragging and dropping a window on the CrOSNext new desk button,
the button's state should updated to `kDragAndDrop`, and its bounds
should be updated correspondingly. When the drag and drop action is
completed, the button should be updated to its the `kExpanded` state.

Also if the desks bar is at the zero state when dragging starts,
animate it to expandeds state immediately when dragging starts. At the
end of the drag, desks bar will stay in the expanded state instead of
switching back to zero state even if there's only one desk.

Bug: b/264706228
Change-Id: Ib2d7d38975b4b8e79b773777b3ff35ed0ff430e1
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4177139
Reviewed-by: Sammie Quon <sammiequon@chromium.org>
Commit-Queue: Connie Xu <conniekxu@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1096484}
  • Loading branch information
conniekxu authored and Chromium LUCI CQ committed Jan 24, 2023
1 parent d33583c commit 0a3b2be
Show file tree
Hide file tree
Showing 11 changed files with 329 additions and 43 deletions.
37 changes: 32 additions & 5 deletions ash/wm/desks/cros_next_desk_button.cc
Expand Up @@ -18,6 +18,7 @@
#include "ui/base/l10n/l10n_util.h"
#include "ui/chromeos/styles/cros_tokens_color_mappings.h"
#include "ui/gfx/canvas.h"
#include "ui/gfx/geometry/insets.h"
#include "ui/gfx/geometry/rounded_corners_f.h"
#include "ui/gfx/text_elider.h"
#include "ui/views/accessibility/view_accessibility.h"
Expand All @@ -34,7 +35,9 @@ constexpr int kDefaultButtonHorizontalPadding = 16;

constexpr int kDefaultDeskButtonMinWidth = 56;

// The desk icon button's corner radius.
constexpr int kIconButtonCornerRadius = 18;
constexpr int kDragAndDropStateCornerRadius = 8;

// Focus rings' corner radius of the desk icon button at different states.
constexpr int kZeroStateFocusRingRadius = 16;
Expand Down Expand Up @@ -136,30 +139,54 @@ CrOSNextDeskIconButton::CrOSNextDeskIconButton(
GetFocusRingRadiusForState(state_));
views::FocusRing::Get(this)->SetHasFocusPredicate([&](views::View* view) {
return IsViewHighlighted() ||
((bar_view_->dragged_item_over_bar() &&
((state_ == State::kDragAndDrop &&
bar_view_->dragged_item_over_bar() &&
IsPointOnButton(bar_view_->last_dragged_item_screen_location())) ||
paint_as_active_);
});
}

CrOSNextDeskIconButton::~CrOSNextDeskIconButton() = default;

// static
int CrOSNextDeskIconButton::GetCornerRadiusOnState(State state) {
switch (state) {
case CrOSNextDeskIconButton::State::kZero:
case CrOSNextDeskIconButton::State::kExpanded:
return kIconButtonCornerRadius;
case CrOSNextDeskIconButton::State::kDragAndDrop:
return kDragAndDropStateCornerRadius;
}
}

void CrOSNextDeskIconButton::UpdateState(State state) {
if (state_ == state) {
return;
}

state_ = state;

SetBackground(views::CreateRoundedRectBackground(
background()->get_color(), GetCornerRadiusOnState(state_)));
views::InstallRoundRectHighlightPathGenerator(
this, gfx::Insets(kFocusRingHaloInset),
GetFocusRingRadiusForState(state_));
}

bool CrOSNextDeskIconButton::IsPointOnButton(
const gfx::Point& screen_location) const {
gfx::Point point_in_view = screen_location;
ConvertPointFromScreen(this, &point_in_view);
return HitTestPoint(point_in_view);
DCHECK(!bar_view_->IsZeroState());

gfx::Rect hit_test_bounds = GetBoundsInScreen();
// Include some pixels on the bottom so the hit region is the same as the desk
// mini view even though the views have different heights.
hit_test_bounds.Inset(gfx::Insets::TLBR(
0, 0,
GetPreferredSize().height() -
bar_view_->mini_views()[0]->GetPreferredSize().height(),
0));

return hit_test_bounds.Contains(screen_location);
}

gfx::Size CrOSNextDeskIconButton::CalculatePreferredSize() const {
Expand All @@ -181,7 +208,7 @@ void CrOSNextDeskIconButton::UpdateFocusState() {
absl::optional<ui::ColorId> new_focus_color_id;

if (IsViewHighlighted() ||
(bar_view_->dragged_item_over_bar() &&
(state_ == State::kDragAndDrop && bar_view_->dragged_item_over_bar() &&
IsPointOnButton(bar_view_->last_dragged_item_screen_location()))) {
new_focus_color_id = ui::kColorAshFocusRing;
} else if (paint_as_active_) {
Expand Down
6 changes: 5 additions & 1 deletion ash/wm/desks/cros_next_desk_button.h
Expand Up @@ -12,7 +12,7 @@

namespace gfx {
struct VectorIcon;
}
} // namespace gfx

namespace ash {

Expand Down Expand Up @@ -79,6 +79,10 @@ class ASH_EXPORT CrOSNextDeskIconButton : public CrOSNextDeskButtonBase {
CrOSNextDeskIconButton& operator=(const CrOSNextDeskIconButton&) = delete;
~CrOSNextDeskIconButton() override;

// Convenient function for returning the desk icon button's corner radius on
// the given `state`.
static int GetCornerRadiusOnState(State state);

State state() const { return state_; }
void set_paint_as_active(bool paint_as_active) {
paint_as_active_ = paint_as_active;
Expand Down
118 changes: 112 additions & 6 deletions ash/wm/desks/desk_mini_view_animations.cc
Expand Up @@ -20,6 +20,8 @@
#include "ui/compositor/layer_animator.h"
#include "ui/compositor/scoped_layer_animation_settings.h"
#include "ui/gfx/geometry/transform_util.h"
#include "ui/views/animation/animation_builder.h"
#include "ui/views/background.h"
#include "ui/views/view.h"

namespace ash {
Expand All @@ -30,6 +32,8 @@ constexpr gfx::Transform kEndTransform;

constexpr base::TimeDelta kExistingMiniViewsAnimationDuration =
base::Milliseconds(250);
constexpr base::TimeDelta kExistingMiniViewsAnimationDurationCrOSNext =
base::Milliseconds(150);

constexpr base::TimeDelta kRemovedMiniViewsFadeOutDuration =
base::Milliseconds(200);
Expand All @@ -40,6 +44,10 @@ constexpr base::TimeDelta kZeroStateAnimationDuration = base::Milliseconds(200);
constexpr base::TimeDelta kZeroStateAnimationDurationCrOSNext =
base::Milliseconds(150);

// Animation durations for scale up and scale down the desk icon button.
constexpr base::TimeDelta kScaleUpDeskIconButton = base::Milliseconds(150);
constexpr base::TimeDelta kScaleDownDeskIconButton = base::Milliseconds(50);

// Scale for entering/exiting zero state.
constexpr float kEnterOrExitZeroStateScale = 0.6f;

Expand All @@ -63,15 +71,19 @@ void AnimateView(views::View* view, const gfx::Transform& begin_transform) {
layer->SetTransform(begin_transform);

ui::ScopedLayerAnimationSettings settings{layer->GetAnimator()};
InitScopedAnimationSettings(&settings, kExistingMiniViewsAnimationDuration);
InitScopedAnimationSettings(&settings,
features::IsJellyrollEnabled()
? kExistingMiniViewsAnimationDurationCrOSNext
: kExistingMiniViewsAnimationDuration);
layer->SetTransform(kEndTransform);
}

// See details at AnimateView.
void AnimateMiniViews(std::vector<DeskMiniView*> mini_views,
const gfx::Transform& begin_transform) {
for (auto* mini_view : mini_views)
for (auto* mini_view : mini_views) {
AnimateView(mini_view, begin_transform);
}
}

// Gets the scale transform for |view|, it can be scale up or scale down. The
Expand Down Expand Up @@ -105,8 +117,8 @@ void ScaleUpAndFadeInView(views::View* view, int bar_x_center) {

ui::ScopedLayerAnimationSettings settings{layer->GetAnimator()};
const base::TimeDelta animation_duration =
features::IsJellyEnabled() ? kZeroStateAnimationDurationCrOSNext
: kZeroStateAnimationDuration;
features::IsJellyrollEnabled() ? kZeroStateAnimationDurationCrOSNext
: kZeroStateAnimationDuration;
InitScopedAnimationSettings(&settings, animation_duration);
layer->SetTransform(kEndTransform);
layer->SetOpacity(1.f);
Expand Down Expand Up @@ -229,8 +241,8 @@ class DesksBarBoundsAnimation : public ui::ImplicitAnimationObserver {
ui::ScopedLayerAnimationSettings settings{
desks_widget->GetLayer()->GetAnimator()};
const base::TimeDelta animation_duration =
features::IsJellyEnabled() ? kZeroStateAnimationDurationCrOSNext
: kZeroStateAnimationDuration;
features::IsJellyrollEnabled() ? kZeroStateAnimationDurationCrOSNext
: kZeroStateAnimationDuration;
InitScopedAnimationSettings(&settings, animation_duration);
settings.AddObserver(this);
desks_widget->SetBounds(target_widget_bounds);
Expand Down Expand Up @@ -260,6 +272,83 @@ class DesksBarBoundsAnimation : public ui::ImplicitAnimationObserver {
DesksBarView* const bar_view_;
};

// A self-deleting class that performs the scale up / down animation for the new
// desk button.
class NewDeskButtonScaleAnimation {
public:
NewDeskButtonScaleAnimation(CrOSNextDeskIconButton* new_desk_button,
const gfx::Transform& scale_transform)
: new_desk_button_(new_desk_button) {
// Please note that since `this` is constructed after `new_desk_button_` is
// laid out in its final position, the target state is its current state.
const CrOSNextDeskIconButton::State target_state =
new_desk_button_->state();
const bool is_scale_up_animation =
target_state == CrOSNextDeskIconButton::State::kDragAndDrop;
const gfx::RoundedCornersF initial_radius =
gfx::RoundedCornersF(CrOSNextDeskIconButton::GetCornerRadiusOnState(
is_scale_up_animation
? CrOSNextDeskIconButton::State::kExpanded
: CrOSNextDeskIconButton::State::kDragAndDrop));

// Since the corner radius of `new_desk_button_` is updated on the state
// changes, to apply the animation for the corner radius change, set and
// apply the corner radius animation on the layer, and set the solid
// background (no corner radius) to the new desk button in the meanwhile. At
// the end of the animation, set the layer's corner radius back to 0, and
// apply the corner radius back to the background. The reason is that the
// focus ring is painted on a layer which is a child of `new_desk_button_`'s
// layer. If `new_desk_button_` has a clip rect, the clip rect will
// affect it's children and the focus ring won't be visible. Please refer to
// the `Layout` function of `FocusRing` for more implementation details.
auto* layer = new_desk_button_->layer();
layer->SetRoundedCornerRadius(initial_radius);
new_desk_button_->SetBackground(views::CreateSolidBackground(
new_desk_button_->background()->get_color()));

layer->SetTransform(scale_transform);

const base::TimeDelta duration = is_scale_up_animation
? kScaleUpDeskIconButton
: kScaleDownDeskIconButton;
const gfx::RoundedCornersF end_radius = gfx::RoundedCornersF(
CrOSNextDeskIconButton::GetCornerRadiusOnState(target_state));
views::AnimationBuilder()
.OnEnded(base::BindOnce(
[](NewDeskButtonScaleAnimation* animation) { delete animation; },
base::Unretained(this)))
.OnAborted(base::BindOnce(
[](NewDeskButtonScaleAnimation* animation) { delete animation; },
base::Unretained(this)))
.SetPreemptionStrategy(
ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET)
.Once()
.SetDuration(duration)
.SetRoundedCorners(layer, end_radius, gfx::Tween::ACCEL_20_DECEL_100)
.SetTransform(layer, kEndTransform, gfx::Tween::ACCEL_20_DECEL_100);
}

NewDeskButtonScaleAnimation(const NewDeskButtonScaleAnimation&) = delete;
NewDeskButtonScaleAnimation& operator=(const NewDeskButtonScaleAnimation&) =
delete;

~NewDeskButtonScaleAnimation() {
if (Shell::Get()->overview_controller()->InOverviewSession()) {
new_desk_button_->layer()->SetRoundedCornerRadius(gfx::RoundedCornersF());
new_desk_button_->SetBackground(views::CreateRoundedRectBackground(
new_desk_button_->background()->get_color(),
CrOSNextDeskIconButton::GetCornerRadiusOnState(
new_desk_button_->state())));
}
}

private:
// `new_desk_button_` is valid through the lifetime of `this `. Since when the
// `new_desk_button` is destroyed, `OnAborted` will be triggered and then the
// destructor of `this` will be triggered.
CrOSNextDeskIconButton* const new_desk_button_;
};

} // namespace

void PerformNewDeskMiniViewAnimation(
Expand Down Expand Up @@ -466,4 +555,21 @@ void PerformLibraryButtonVisibilityAnimation(
AnimateView(new_desk_button, translation);
}

void PerformNewDeskButtonScaleAnimationCrOSNext(
DesksBarView* bar_view,
const gfx::Transform& new_desk_button_rects_transform,
int shift_x) {
new NewDeskButtonScaleAnimation(bar_view->new_desk_button(),
new_desk_button_rects_transform);
gfx::Transform left_begin_transform;
left_begin_transform.Translate(shift_x, 0);
gfx::Transform right_begin_transform;
right_begin_transform.Translate(-shift_x, 0);

AnimateMiniViews(bar_view->mini_views(), left_begin_transform);
if (auto* library_button = bar_view->library_button()) {
AnimateView(library_button, right_begin_transform);
}
}

} // namespace ash
17 changes: 16 additions & 1 deletion ash/wm/desks/desk_mini_view_animations.h
Expand Up @@ -8,9 +8,13 @@
#include <memory>
#include <vector>

namespace gfx {
class Transform;
} // namespace gfx

namespace views {
class View;
}
} // namespace views

namespace ash {

Expand Down Expand Up @@ -111,6 +115,17 @@ void PerformLibraryButtonVisibilityAnimation(
views::View* new_desk_button,
int shift_x);

// Performs the `new_desk_button_` scale animation based on the given arguments.
// It also shifts the mini views to the left and the library button to the right
// by `shift_x` with animation.
// * Notes:
// - It assumes all the mini views in `bar_view`, new desk button and library
// button have been laid out in their final positions.
void PerformNewDeskButtonScaleAnimationCrOSNext(
DesksBarView* bar_view,
const gfx::Transform& new_desk_button_rects_transform,
int shift_x);

} // namespace ash

#endif // ASH_WM_DESKS_DESK_MINI_VIEW_ANIMATIONS_H_

0 comments on commit 0a3b2be

Please sign in to comment.