1 // Copyright 2018 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/login/ui/arrow_button_view.h"
6 
7 #include <utility>
8 
9 #include "ash/resources/vector_icons/vector_icons.h"
10 #include "ash/style/ash_color_provider.h"
11 #include "base/time/time.h"
12 #include "cc/paint/paint_flags.h"
13 #include "ui/accessibility/ax_node_data.h"
14 #include "ui/gfx/animation/multi_animation.h"
15 #include "ui/gfx/animation/tween.h"
16 #include "ui/gfx/canvas.h"
17 #include "ui/gfx/color_palette.h"
18 #include "ui/gfx/geometry/rect.h"
19 #include "ui/gfx/paint_vector_icon.h"
20 #include "ui/gfx/skia_util.h"
21 #include "ui/views/controls/highlight_path_generator.h"
22 
23 namespace ash {
24 namespace {
25 
26 // Arrow icon size.
27 constexpr int kArrowIconSizeDp = 20;
28 constexpr int kArrowIconBackroundRadius = 25;
29 // How long does a single step of the loading animation take - i.e., the time it
30 // takes for the arc to grow from a point to a full circle.
31 constexpr base::TimeDelta kLoadingAnimationStepDuration =
32     base::TimeDelta::FromSeconds(2);
33 
PaintLoadingArc(gfx::Canvas * canvas,const gfx::Rect & bounds,double loading_fraction)34 void PaintLoadingArc(gfx::Canvas* canvas,
35                      const gfx::Rect& bounds,
36                      double loading_fraction) {
37   gfx::Rect oval = bounds;
38   // Inset to make sure the whole arc is inside the visible rect.
39   oval.Inset(/*horizontal=*/1, /*vertical=*/1);
40 
41   SkPath path;
42   path.arcTo(RectToSkRect(oval), /*startAngle=*/-90,
43              /*sweepAngle=*/360 * loading_fraction, /*forceMoveTo=*/true);
44 
45   cc::PaintFlags flags;
46   flags.setColor(gfx::kGoogleGrey100);
47   flags.setStyle(cc::PaintFlags::kStroke_Style);
48   flags.setAntiAlias(true);
49   canvas->DrawPath(path, flags);
50 }
51 
52 }  // namespace
53 
ArrowButtonView(PressedCallback callback,int size)54 ArrowButtonView::ArrowButtonView(PressedCallback callback, int size)
55     : LoginButton(std::move(callback)), size_(size) {
56   SetPreferredSize(gfx::Size(size, size));
57   SetFocusBehavior(FocusBehavior::ALWAYS);
58 
59   // Layer rendering is needed for animation.
60   SetPaintToLayer();
61   layer()->SetFillsBoundsOpaquely(false);
62 
63   AshColorProvider::Get()->DecorateIconButton(
64       this, kLockScreenArrowIcon, /*toggled_=*/false, kArrowIconSizeDp);
65   focus_ring()->SetPathGenerator(
66       std::make_unique<views::FixedSizeCircleHighlightPathGenerator>(
67           kArrowIconBackroundRadius));
68 
69   SetBackgroundColor(AshColorProvider::Get()->GetControlsLayerColor(
70       AshColorProvider::ControlsLayerType::kControlBackgroundColorInactive));
71 }
72 
73 ArrowButtonView::~ArrowButtonView() = default;
74 
PaintButtonContents(gfx::Canvas * canvas)75 void ArrowButtonView::PaintButtonContents(gfx::Canvas* canvas) {
76   const gfx::Rect rect(GetContentsBounds());
77 
78   // Draw background.
79   cc::PaintFlags flags;
80   flags.setAntiAlias(true);
81   flags.setColor(background_color_);
82   flags.setStyle(cc::PaintFlags::kFill_Style);
83   canvas->DrawCircle(gfx::PointF(rect.CenterPoint()), size_ / 2, flags);
84 
85   // Draw arrow icon.
86   views::ImageButton::PaintButtonContents(canvas);
87 
88   // Draw the arc of the loading animation.
89   if (loading_animation_)
90     PaintLoadingArc(canvas, rect, loading_animation_->GetCurrentValue());
91 }
92 
GetAccessibleNodeData(ui::AXNodeData * node_data)93 void ArrowButtonView::GetAccessibleNodeData(ui::AXNodeData* node_data) {
94   LoginButton::GetAccessibleNodeData(node_data);
95   // TODO(tbarzic): Fix this - https://crbug.com/961930.
96   if (GetAccessibleName().empty())
97     node_data->SetNameExplicitlyEmpty();
98 }
99 
GetClassName() const100 const char* ArrowButtonView::GetClassName() const {
101   return "ArrowButtonView";
102 }
103 
SetBackgroundColor(SkColor color)104 void ArrowButtonView::SetBackgroundColor(SkColor color) {
105   background_color_ = color;
106   SchedulePaint();
107 }
108 
EnableLoadingAnimation(bool enabled)109 void ArrowButtonView::EnableLoadingAnimation(bool enabled) {
110   if (!enabled) {
111     if (!loading_animation_)
112       return;
113     loading_animation_.reset();
114     SchedulePaint();
115     return;
116   }
117 
118   if (loading_animation_)
119     return;
120 
121   // Use MultiAnimation in order to have a continuously running analog of
122   // LinearAnimation.
123   loading_animation_ = std::make_unique<gfx::MultiAnimation>(
124       gfx::MultiAnimation::Parts{
125           gfx::MultiAnimation::Part(kLoadingAnimationStepDuration,
126                                     gfx::Tween::LINEAR),
127       },
128       gfx::MultiAnimation::kDefaultTimerInterval);
129   loading_animation_->set_delegate(&loading_animation_delegate_);
130   loading_animation_->Start();
131 }
132 
LoadingAnimationDelegate(ArrowButtonView * owner)133 ArrowButtonView::LoadingAnimationDelegate::LoadingAnimationDelegate(
134     ArrowButtonView* owner)
135     : owner_(owner) {}
136 
137 ArrowButtonView::LoadingAnimationDelegate::~LoadingAnimationDelegate() =
138     default;
139 
AnimationProgressed(const gfx::Animation *)140 void ArrowButtonView::LoadingAnimationDelegate::AnimationProgressed(
141     const gfx::Animation* /*animation*/) {
142   owner_->SchedulePaint();
143 }
144 
145 }  // namespace ash
146