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