#include "ash/wm/splitview/split_view_divider_handler_view.h"
#include "ash/display/screen_orientation_controller.h"
#include "ash/shell.h"
#include "ash/style/ash_color_id.h"
#include "ash/wm/splitview/split_view_constants.h"
#include "ash/wm/splitview/split_view_utils.h"
#include "base/memory/raw_ptr.h"
#include "base/timer/timer.h"
#include "chromeos/constants/chromeos_features.h"
#include "ui/chromeos/styles/cros_tokens_color_mappings.h"
#include "ui/color/color_id.h"
#include "ui/compositor/layer.h"
#include "ui/gfx/animation/animation_delegate.h"
#include "ui/gfx/animation/slide_animation.h"
#include "ui/views/background.h"
namespace ash {
class SplitViewDividerHandlerView::SelectionAnimation
: public gfx::SlideAnimation,
public gfx::AnimationDelegate {
public:
SelectionAnimation(SplitViewDividerHandlerView* white_handler_view)
: gfx::SlideAnimation(this), white_handler_view_(white_handler_view) {
SetSlideDuration(kSplitviewDividerSelectionStatusChangeDuration);
SetTweenType(gfx::Tween::EASE_IN);
}
SelectionAnimation(const SelectionAnimation&) = delete;
SelectionAnimation& operator=(const SelectionAnimation&) = delete;
~SelectionAnimation() override = default;
void UpdateWhiteHandlerBounds() {
white_handler_view_->SetBounds(
CurrentValueBetween(kSplitviewWhiteBarShortSideLength,
kSplitviewWhiteBarRadius * 2),
CurrentValueBetween(kSplitviewWhiteBarLongSideLength,
kSplitviewWhiteBarRadius * 2),
0);
}
private:
void AnimationProgressed(const gfx::Animation* animation) override {
UpdateWhiteHandlerBounds();
white_handler_view_->UpdateCornerRadius(CurrentValueBetween(
kSplitviewWhiteBarCornerRadius, kSplitviewWhiteBarRadius));
}
raw_ptr<SplitViewDividerHandlerView, ExperimentalAsh> white_handler_view_;
};
class SplitViewDividerHandlerView::SpawningAnimation
: public gfx::SlideAnimation,
public gfx::AnimationDelegate {
public:
SpawningAnimation(SplitViewDividerHandlerView* white_handler_view,
int divider_signed_offset)
: gfx::SlideAnimation(this),
white_handler_view_(white_handler_view),
spawn_signed_offset_(divider_signed_offset +
(divider_signed_offset > 0
? kSplitviewWhiteBarSpawnUnsignedOffset
: -kSplitviewWhiteBarSpawnUnsignedOffset)) {
SetSlideDuration(kSplitviewDividerSpawnDuration);
SetTweenType(gfx::Tween::LINEAR_OUT_SLOW_IN);
}
SpawningAnimation(const SpawningAnimation&) = delete;
SpawningAnimation& operator=(const SpawningAnimation&) = delete;
~SpawningAnimation() override = default;
void Activate() {
white_handler_view_->SetVisible(false);
delay_timer_.Start(FROM_HERE, kSplitviewDividerSpawnDelay, this,
&SpawningAnimation::StartAnimation);
}
bool IsActive() const { return delay_timer_.IsRunning() || is_animating(); }
void UpdateWhiteHandlerBounds() {
DCHECK(IsActive());
white_handler_view_->SetBounds(
kSplitviewWhiteBarShortSideLength,
CurrentValueBetween(kSplitviewWhiteBarSpawnLongSideLength,
kSplitviewWhiteBarLongSideLength),
CurrentValueBetween(spawn_signed_offset_, 0));
}
private:
void StartAnimation() {
DCHECK(!white_handler_view_->GetVisible());
white_handler_view_->SetVisible(true);
DCHECK(!is_animating());
Show();
DCHECK_EQ(0.0, GetCurrentValue());
UpdateWhiteHandlerBounds();
}
void AnimationProgressed(const gfx::Animation* animation) override {
UpdateWhiteHandlerBounds();
}
raw_ptr<SplitViewDividerHandlerView, ExperimentalAsh> white_handler_view_;
int spawn_signed_offset_;
base::OneShotTimer delay_timer_;
};
SplitViewDividerHandlerView::SplitViewDividerHandlerView()
: selection_animation_(std::make_unique<SelectionAnimation>(this)) {
SetPaintToLayer();
SetBackground(views::CreateThemedRoundedRectBackground(
chromeos::features::IsJellyrollEnabled()
? static_cast<ui::ColorId>(cros_tokens::kCrosSysOnSurface)
: kColorAshIconColorPrimary,
kSplitviewWhiteBarCornerRadius));
}
SplitViewDividerHandlerView::~SplitViewDividerHandlerView() = default;
void SplitViewDividerHandlerView::DoSpawningAnimation(
int divider_signed_offset) {
spawning_animation_ =
std::make_unique<SpawningAnimation>(this, divider_signed_offset);
spawning_animation_->Activate();
}
void SplitViewDividerHandlerView::Refresh(bool is_resizing) {
spawning_animation_.reset();
SetVisible(true);
selection_animation_->UpdateWhiteHandlerBounds();
if (is_resizing)
selection_animation_->Show();
else
selection_animation_->Hide();
}
void SplitViewDividerHandlerView::UpdateCornerRadius(float radius) {
layer()->SetRoundedCornerRadius(gfx::RoundedCornersF{radius});
}
void SplitViewDividerHandlerView::SetBounds(int short_length,
int long_length,
int signed_offset) {
const bool landscape = IsCurrentScreenOrientationLandscape();
gfx::Rect bounds = landscape ? gfx::Rect(short_length, long_length)
: gfx::Rect(long_length, short_length);
bounds.Offset(parent()->GetLocalBounds().CenterPoint() -
bounds.CenterPoint() +
(landscape ? gfx::Vector2d(signed_offset, 0)
: gfx::Vector2d(0, signed_offset)));
SetBoundsRect(bounds);
}
void SplitViewDividerHandlerView::OnPaint(gfx::Canvas* canvas) {
views::View::OnPaint(canvas);
canvas->DrawColor(SK_ColorTRANSPARENT, SkBlendMode::kSrc);
views::View::OnPaint(canvas);
}
}