Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(414)

Side by Side Diff: ui/views/controls/button/toggle_button.cc

Issue 2396133005: [ash-md] Animates ToggleButton highlight to move it in sync with the thumb (Closed)
Patch Set: [ash-md] Animates ToggleButton highlight to move it in sync with the thumb (better destruction sequ… Created 4 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2016 The Chromium Authors. All rights reserved. 1 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "ui/views/controls/button/toggle_button.h" 5 #include "ui/views/controls/button/toggle_button.h"
6 6
7 #include "third_party/skia/include/core/SkDrawLooper.h" 7 #include "third_party/skia/include/core/SkDrawLooper.h"
8 #include "third_party/skia/include/core/SkPaint.h" 8 #include "third_party/skia/include/core/SkPaint.h"
9 #include "ui/gfx/canvas.h" 9 #include "ui/gfx/canvas.h"
10 #include "ui/gfx/color_palette.h" 10 #include "ui/gfx/color_palette.h"
(...skipping 16 matching lines...) Expand all
27 const int kThumbHorizontalMargin = 4; 27 const int kThumbHorizontalMargin = 4;
28 // Margin from top/bottom edge of thumb to top/bottom edge of view. 28 // Margin from top/bottom edge of thumb to top/bottom edge of view.
29 const int kThumbVerticalMargin = 3; 29 const int kThumbVerticalMargin = 3;
30 30
31 // TODO(estade): get the base color (black) from the theme? 31 // TODO(estade): get the base color (black) from the theme?
32 const SkColor kTrackOffColor = 32 const SkColor kTrackOffColor =
33 SkColorSetA(SK_ColorBLACK, gfx::kDisabledControlAlpha); 33 SkColorSetA(SK_ColorBLACK, gfx::kDisabledControlAlpha);
34 34
35 } // namespace 35 } // namespace
36 36
37 // Class representing the thumb. When the thumb is clicked it is separated into
38 // its own layer and the ink drop layer is made a child of the thumb layer
39 // allowing the two to animate in sync.
40 class ToggleButton::ThumbView : public views::View {
41 public:
42 ThumbView() : color_ratio_(0.) {}
43 ~ThumbView() override {}
44
45 void AddInkDropLayer(ui::Layer* ink_drop_layer) {
Evan Stade 2016/10/17 15:37:58 if ThumbView were an InkDropHostView could we not
varkha 2016/10/17 16:12:53 Yes, but this would mean we would have to fix the
Evan Stade 2016/10/18 13:13:15 I didn't mean to replace the ToggleButton as the I
46 SetPaintToLayer(true);
47 layer()->SetFillsBoundsOpaquely(false);
48 layer()->Add(ink_drop_layer);
49 }
50
51 void RemoveInkDropLayer(ui::Layer* ink_drop_layer) {
52 layer()->Remove(ink_drop_layer);
53 SetPaintToLayer(false);
54 }
55
56 void Update(const gfx::Rect& bounds, double color_ratio) {
57 SetBoundsRect(bounds);
58 color_ratio_ = color_ratio;
59 SchedulePaint();
60 }
61
62 private:
63 // views::View:
64 const char* GetClassName() const override {
65 return "ToggleButton::ThumbView";
66 }
67
68 void OnPaint(gfx::Canvas* canvas) override {
69 std::vector<gfx::ShadowValue> shadows;
70 shadows.emplace_back(gfx::Vector2d(0, 1), 4.f,
71 SkColorSetA(SK_ColorBLACK, 0x99));
72 SkPaint thumb_paint;
73 thumb_paint.setLooper(gfx::CreateShadowDrawLooperCorrectBlur(shadows));
74 thumb_paint.setStyle(SkPaint::kFill_Style);
75 thumb_paint.setAntiAlias(true);
76 const SkColor thumb_on_color = GetNativeTheme()->GetSystemColor(
77 ui::NativeTheme::kColorId_ProminentButtonColor);
78 // TODO(estade): get this color from the theme?
79 const SkColor thumb_off_color = SK_ColorWHITE;
80 const SkAlpha blend = static_cast<SkAlpha>(SK_AlphaOPAQUE * color_ratio_);
81 thumb_paint.setColor(
82 color_utils::AlphaBlend(thumb_on_color, thumb_off_color, blend));
83 gfx::Rect thumb_bounds = GetLocalBounds();
84 thumb_bounds.Inset(gfx::Insets(kThumbVerticalMargin));
85 canvas->DrawCircle(gfx::RectF(thumb_bounds).CenterPoint(),
86 thumb_bounds.height() / 2.f, thumb_paint);
87 }
88
89 // Color ratio between 0 and 1 that controls the thumb color.
90 double color_ratio_;
91
92 DISALLOW_COPY_AND_ASSIGN(ThumbView);
93 };
94
95 // static
96 const char ToggleButton::kViewClassName[] = "ToggleButton";
97
37 ToggleButton::ToggleButton(ButtonListener* listener) 98 ToggleButton::ToggleButton(ButtonListener* listener)
38 : CustomButton(listener), is_on_(false), slide_animation_(this) { 99 : CustomButton(listener),
100 is_on_(false),
101 slide_animation_(this),
102 thumb_view_(new ToggleButton::ThumbView()) {
39 slide_animation_.SetSlideDuration(80 /* ms */); 103 slide_animation_.SetSlideDuration(80 /* ms */);
40 slide_animation_.SetTweenType(gfx::Tween::LINEAR); 104 slide_animation_.SetTweenType(gfx::Tween::LINEAR);
41 SetBorder(Border::CreateEmptyBorder( 105 SetBorder(Border::CreateEmptyBorder(
42 gfx::Insets(kTrackVerticalMargin, kTrackHorizontalMargin))); 106 gfx::Insets(kTrackVerticalMargin, kTrackHorizontalMargin)));
107 AddChildView(thumb_view_.get());
43 SetInkDropMode(InkDropMode::ON); 108 SetInkDropMode(InkDropMode::ON);
44 set_has_ink_drop_action_on_click(true); 109 set_has_ink_drop_action_on_click(true);
45 } 110 }
46 111
47 ToggleButton::~ToggleButton() {} 112 ToggleButton::~ToggleButton() {
113 // Destroying ink drop early allows ink drop layer to be properly removed,
114 SetInkDropMode(InkDropMode::OFF);
115 }
48 116
49 void ToggleButton::SetIsOn(bool is_on, bool animate) { 117 void ToggleButton::SetIsOn(bool is_on, bool animate) {
50 if (is_on_ == is_on) 118 if (is_on_ == is_on)
51 return; 119 return;
52 120
53 is_on_ = is_on; 121 is_on_ = is_on;
54 if (!animate) 122 if (!animate)
55 slide_animation_.Reset(is_on_ ? 1.0 : 0.0); 123 slide_animation_.Reset(is_on_ ? 1.0 : 0.0);
56 else if (is_on_) 124 else if (is_on_)
57 slide_animation_.Show(); 125 slide_animation_.Show();
58 else 126 else
59 slide_animation_.Hide(); 127 slide_animation_.Hide();
60 } 128 }
61 129
130 gfx::Rect ToggleButton::GetThumbBounds() const {
131 gfx::Rect thumb_bounds = GetLocalBounds();
132 thumb_bounds.Inset(gfx::Insets(kThumbVerticalMargin, kThumbHorizontalMargin));
133 thumb_bounds.set_x(thumb_bounds.x() +
134 slide_animation_.GetCurrentValue() *
135 (thumb_bounds.width() - thumb_bounds.height()));
136 // The thumb is a circle, so the width should match the height.
137 thumb_bounds.set_width(thumb_bounds.height());
138 thumb_bounds.set_x(GetMirroredXForRect(thumb_bounds));
139 return thumb_bounds;
140 }
141
142 void ToggleButton::UpdateThumb() {
143 gfx::Rect thumb_bounds = GetThumbBounds();
144 thumb_bounds.Inset(gfx::Insets(-kThumbVerticalMargin));
145 thumb_view_->Update(thumb_bounds, slide_animation_.GetCurrentValue());
146 }
147
62 gfx::Size ToggleButton::GetPreferredSize() const { 148 gfx::Size ToggleButton::GetPreferredSize() const {
63 gfx::Rect rect(0, 0, kTrackWidth, kTrackHeight); 149 gfx::Rect rect(0, 0, kTrackWidth, kTrackHeight);
64 if (border()) 150 if (border())
65 rect.Inset(-border()->GetInsets()); 151 rect.Inset(-border()->GetInsets());
66 return rect.size(); 152 return rect.size();
67 } 153 }
68 154
155 const char* ToggleButton::GetClassName() const {
156 return kViewClassName;
157 }
158
69 void ToggleButton::OnPaint(gfx::Canvas* canvas) { 159 void ToggleButton::OnPaint(gfx::Canvas* canvas) {
70 SkAlpha blend = 160 // Paint the toggle track.
71 static_cast<SkAlpha>(SK_AlphaOPAQUE * slide_animation_.GetCurrentValue());
72
73 // Track.
74 gfx::RectF track_rect(GetContentsBounds()); 161 gfx::RectF track_rect(GetContentsBounds());
75 SkPaint track_paint; 162 SkPaint track_paint;
76 track_paint.setAntiAlias(true); 163 track_paint.setAntiAlias(true);
77 const SkColor track_on_color = 164 const SkColor track_on_color =
78 SkColorSetA(GetNativeTheme()->GetSystemColor( 165 SkColorSetA(GetNativeTheme()->GetSystemColor(
79 ui::NativeTheme::kColorId_ProminentButtonColor), 166 ui::NativeTheme::kColorId_ProminentButtonColor),
80 0xFF / 2); 167 0xFF / 2);
81 track_paint.setColor( 168 const double color_ratio = slide_animation_.GetCurrentValue();
82 color_utils::AlphaBlend(track_on_color, kTrackOffColor, blend)); 169 track_paint.setColor(color_utils::AlphaBlend(
170 track_on_color, kTrackOffColor,
171 static_cast<SkAlpha>(SK_AlphaOPAQUE * color_ratio)));
83 canvas->DrawRoundRect(track_rect, track_rect.height() / 2, track_paint); 172 canvas->DrawRoundRect(track_rect, track_rect.height() / 2, track_paint);
84
85 // Thumb.
86 gfx::Rect thumb_bounds = GetThumbBounds();
87 SkPaint thumb_paint;
88 std::vector<gfx::ShadowValue> shadows;
89 shadows.emplace_back(gfx::Vector2d(0, 1), 4.f,
90 SkColorSetA(SK_ColorBLACK, 0x99));
91 thumb_paint.setLooper(gfx::CreateShadowDrawLooperCorrectBlur(shadows));
92 thumb_paint.setStyle(SkPaint::kFill_Style);
93 thumb_paint.setAntiAlias(true);
94 const SkColor thumb_on_color = GetNativeTheme()->GetSystemColor(
95 ui::NativeTheme::kColorId_ProminentButtonColor);
96 // TODO(estade): get this color from the theme?
97 const SkColor thumb_off_color = SK_ColorWHITE;
98 thumb_paint.setColor(
99 color_utils::AlphaBlend(thumb_on_color, thumb_off_color, blend));
100 canvas->DrawCircle(gfx::RectF(thumb_bounds).CenterPoint(),
101 thumb_bounds.height() / 2.f, thumb_paint);
102 } 173 }
103 174
104 void ToggleButton::NotifyClick(const ui::Event& event) { 175 void ToggleButton::NotifyClick(const ui::Event& event) {
105 SetIsOn(!is_on(), true); 176 SetIsOn(!is_on(), true);
106 CustomButton::NotifyClick(event); 177 CustomButton::NotifyClick(event);
107 } 178 }
108 179
180 void ToggleButton::OnBoundsChanged(const gfx::Rect& previous_bounds) {
181 UpdateThumb();
182 }
183
109 void ToggleButton::OnNativeThemeChanged(const ui::NativeTheme* theme) { 184 void ToggleButton::OnNativeThemeChanged(const ui::NativeTheme* theme) {
110 SchedulePaint(); 185 SchedulePaint();
111 } 186 }
112 187
188 void ToggleButton::AddInkDropLayer(ui::Layer* ink_drop_layer) {
189 thumb_view_->AddInkDropLayer(ink_drop_layer);
190 UpdateThumb();
191 SchedulePaint();
192 }
193
194 void ToggleButton::RemoveInkDropLayer(ui::Layer* ink_drop_layer) {
195 thumb_view_->RemoveInkDropLayer(ink_drop_layer);
196 SchedulePaint();
197 }
198
113 std::unique_ptr<InkDropRipple> ToggleButton::CreateInkDropRipple() const { 199 std::unique_ptr<InkDropRipple> ToggleButton::CreateInkDropRipple() const {
114 return CreateDefaultInkDropRipple(GetThumbBounds().CenterPoint()); 200 const int radius = (kTrackHeight + kTrackVerticalMargin * 2) / 2;
201 return CreateDefaultInkDropRipple(gfx::Point(radius, radius));
115 } 202 }
116 203
117 SkColor ToggleButton::GetInkDropBaseColor() const { 204 SkColor ToggleButton::GetInkDropBaseColor() const {
118 return is_on() 205 return is_on()
119 ? GetNativeTheme()->GetSystemColor( 206 ? GetNativeTheme()->GetSystemColor(
120 ui::NativeTheme::kColorId_ProminentButtonColor) 207 ui::NativeTheme::kColorId_ProminentButtonColor)
121 : kTrackOffColor; 208 : kTrackOffColor;
122 } 209 }
123 210
124 bool ToggleButton::ShouldShowInkDropHighlight() const { 211 bool ToggleButton::ShouldShowInkDropHighlight() const {
125 return false; 212 return false;
126 } 213 }
127 214
128 void ToggleButton::AnimationProgressed(const gfx::Animation* animation) { 215 void ToggleButton::AnimationProgressed(const gfx::Animation* animation) {
129 if (animation == &slide_animation_) 216 if (animation == &slide_animation_) {
217 // TODO(varkha, estade): The thumb is using its own view. Investigate if
218 // repainting in every animation step to update colors could be avoided.
Evan Stade 2016/10/17 15:37:58 I don't understand this comment. How can we avoid
varkha 2016/10/17 16:12:53 I think sadrul@ was asking if some layer animation
219 UpdateThumb();
130 SchedulePaint(); 220 SchedulePaint();
131 else 221 return;
132 CustomButton::AnimationProgressed(animation); 222 }
133 } 223 CustomButton::AnimationProgressed(animation);
134
135 gfx::Rect ToggleButton::GetThumbBounds() const {
136 gfx::Rect thumb_bounds = GetLocalBounds();
137 thumb_bounds.Inset(gfx::Insets(kThumbVerticalMargin, kThumbHorizontalMargin));
138 thumb_bounds.set_x(thumb_bounds.x() +
139 slide_animation_.GetCurrentValue() *
140 (thumb_bounds.width() - thumb_bounds.height()));
141 // The thumb is a circle, so the width should match the height.
142 thumb_bounds.set_width(thumb_bounds.height());
143 thumb_bounds.set_x(GetMirroredXForRect(thumb_bounds));
144 return thumb_bounds;
145 } 224 }
146 225
147 } // namespace views 226 } // namespace views
OLDNEW
« no previous file with comments | « ui/views/controls/button/toggle_button.h ('k') | ui/views/controls/button/toggle_button_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698