1 // Copyright 2019 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "ash/wm/splitview/split_view_divider_handler_view.h"
6 
7 #include "ash/display/screen_orientation_controller.h"
8 #include "ash/shell.h"
9 #include "ash/style/ash_color_provider.h"
10 #include "ash/wm/splitview/split_view_constants.h"
11 #include "ash/wm/splitview/split_view_utils.h"
12 #include "base/timer/timer.h"
13 #include "ui/gfx/animation/animation_delegate.h"
14 #include "ui/gfx/animation/slide_animation.h"
15 #include "ui/views/background.h"
16 
17 namespace ash {
18 
19 namespace {
20 
GetBackgroundColor()21 SkColor GetBackgroundColor() {
22   return AshColorProvider::Get()->GetContentLayerColor(
23       AshColorProvider::ContentLayerType::kIconColorPrimary);
24 }
25 
26 }  // namespace
27 
28 class SplitViewDividerHandlerView::SelectionAnimation
29     : public gfx::SlideAnimation,
30       public gfx::AnimationDelegate {
31  public:
SelectionAnimation(SplitViewDividerHandlerView * white_handler_view)32   SelectionAnimation(SplitViewDividerHandlerView* white_handler_view)
33       : gfx::SlideAnimation(this), white_handler_view_(white_handler_view) {
34     SetSlideDuration(kSplitviewDividerSelectionStatusChangeDuration);
35     SetTweenType(gfx::Tween::EASE_IN);
36   }
37 
38   ~SelectionAnimation() override = default;
39 
UpdateWhiteHandlerBounds()40   void UpdateWhiteHandlerBounds() {
41     white_handler_view_->SetBounds(
42         CurrentValueBetween(kSplitviewWhiteBarShortSideLength,
43                             kSplitviewWhiteBarRadius * 2),
44         CurrentValueBetween(kSplitviewWhiteBarLongSideLength,
45                             kSplitviewWhiteBarRadius * 2),
46         /*signed_offset=*/0);
47   }
48 
49  private:
50   // gfx::AnimationDelegate:
AnimationProgressed(const gfx::Animation * animation)51   void AnimationProgressed(const gfx::Animation* animation) override {
52     UpdateWhiteHandlerBounds();
53     white_handler_view_->UpdateCornerRadius(CurrentValueBetween(
54         kSplitviewWhiteBarCornerRadius, kSplitviewWhiteBarRadius));
55   }
56 
57   SplitViewDividerHandlerView* white_handler_view_;
58 
59   DISALLOW_COPY_AND_ASSIGN(SelectionAnimation);
60 };
61 
62 class SplitViewDividerHandlerView::SpawningAnimation
63     : public gfx::SlideAnimation,
64       public gfx::AnimationDelegate {
65  public:
SpawningAnimation(SplitViewDividerHandlerView * white_handler_view,int divider_signed_offset)66   SpawningAnimation(SplitViewDividerHandlerView* white_handler_view,
67                     int divider_signed_offset)
68       : gfx::SlideAnimation(this),
69         white_handler_view_(white_handler_view),
70         spawn_signed_offset_(divider_signed_offset +
71                              (divider_signed_offset > 0
72                                   ? kSplitviewWhiteBarSpawnUnsignedOffset
73                                   : -kSplitviewWhiteBarSpawnUnsignedOffset)) {
74     SetSlideDuration(kSplitviewDividerSpawnDuration);
75     SetTweenType(gfx::Tween::LINEAR_OUT_SLOW_IN);
76   }
77 
78   ~SpawningAnimation() override = default;
79 
Activate()80   void Activate() {
81     white_handler_view_->SetVisible(false);
82     delay_timer_.Start(FROM_HERE, kSplitviewDividerSpawnDelay, this,
83                        &SpawningAnimation::StartAnimation);
84   }
85 
IsActive() const86   bool IsActive() const { return delay_timer_.IsRunning() || is_animating(); }
87 
UpdateWhiteHandlerBounds()88   void UpdateWhiteHandlerBounds() {
89     DCHECK(IsActive());
90     white_handler_view_->SetBounds(
91         kSplitviewWhiteBarShortSideLength,
92         CurrentValueBetween(kSplitviewWhiteBarSpawnLongSideLength,
93                             kSplitviewWhiteBarLongSideLength),
94         CurrentValueBetween(spawn_signed_offset_, 0));
95   }
96 
97  private:
StartAnimation()98   void StartAnimation() {
99     DCHECK(!white_handler_view_->GetVisible());
100     white_handler_view_->SetVisible(true);
101     DCHECK(!is_animating());
102     Show();
103     DCHECK_EQ(0.0, GetCurrentValue());
104     UpdateWhiteHandlerBounds();
105   }
106 
107   // gfx::AnimationDelegate:
AnimationProgressed(const gfx::Animation * animation)108   void AnimationProgressed(const gfx::Animation* animation) override {
109     UpdateWhiteHandlerBounds();
110   }
111 
112   SplitViewDividerHandlerView* white_handler_view_;
113   int spawn_signed_offset_;
114   base::OneShotTimer delay_timer_;
115 
116   DISALLOW_COPY_AND_ASSIGN(SpawningAnimation);
117 };
118 
SplitViewDividerHandlerView()119 SplitViewDividerHandlerView::SplitViewDividerHandlerView()
120     : selection_animation_(std::make_unique<SelectionAnimation>(this)) {
121   SetPaintToLayer();
122   SetBackground(views::CreateRoundedRectBackground(
123       GetBackgroundColor(), kSplitviewWhiteBarCornerRadius));
124 }
125 
126 SplitViewDividerHandlerView::~SplitViewDividerHandlerView() = default;
127 
DoSpawningAnimation(int divider_signed_offset)128 void SplitViewDividerHandlerView::DoSpawningAnimation(
129     int divider_signed_offset) {
130   spawning_animation_ =
131       std::make_unique<SpawningAnimation>(this, divider_signed_offset);
132   spawning_animation_->Activate();
133 }
134 
Refresh(bool is_resizing)135 void SplitViewDividerHandlerView::Refresh(bool is_resizing) {
136   spawning_animation_.reset();
137   SetVisible(true);
138   selection_animation_->UpdateWhiteHandlerBounds();
139   if (is_resizing)
140     selection_animation_->Show();
141   else
142     selection_animation_->Hide();
143 }
144 
UpdateCornerRadius(int radius)145 void SplitViewDividerHandlerView::UpdateCornerRadius(int radius) {
146   layer()->SetRoundedCornerRadius(gfx::RoundedCornersF{radius});
147 }
148 
SetBounds(int short_length,int long_length,int signed_offset)149 void SplitViewDividerHandlerView::SetBounds(int short_length,
150                                             int long_length,
151                                             int signed_offset) {
152   const bool landscape = IsCurrentScreenOrientationLandscape();
153   gfx::Rect bounds = landscape ? gfx::Rect(short_length, long_length)
154                                : gfx::Rect(long_length, short_length);
155   bounds.Offset(parent()->GetLocalBounds().CenterPoint() -
156                 bounds.CenterPoint() +
157                 (landscape ? gfx::Vector2d(signed_offset, 0)
158                            : gfx::Vector2d(0, signed_offset)));
159   SetBoundsRect(bounds);
160 }
161 
OnPaint(gfx::Canvas * canvas)162 void SplitViewDividerHandlerView::OnPaint(gfx::Canvas* canvas) {
163   views::View::OnPaint(canvas);
164   // It's needed to avoid artifacts when tapping on the divider quickly.
165   canvas->DrawColor(SK_ColorTRANSPARENT, SkBlendMode::kSrc);
166   views::View::OnPaint(canvas);
167 }
168 
OnThemeChanged()169 void SplitViewDividerHandlerView::OnThemeChanged() {
170   views::View::OnThemeChanged();
171   background()->SetNativeControlColor(GetBackgroundColor());
172   SchedulePaint();
173 }
174 
175 }  // namespace ash
176