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

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

Issue 2440723003: Tweaks to ToggleButton details. (Closed)
Patch Set: remove a little more Created 4 years, 1 month 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
« no previous file with comments | « ui/views/controls/button/toggle_button.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 10 matching lines...) Expand all
21 const int kTrackWidth = 28; 21 const int kTrackWidth = 28;
22 // Margins from edge of track to edge of view. 22 // Margins from edge of track to edge of view.
23 const int kTrackVerticalMargin = 5; 23 const int kTrackVerticalMargin = 5;
24 const int kTrackHorizontalMargin = 6; 24 const int kTrackHorizontalMargin = 6;
25 // Margin from edge of thumb to closest edge of view. Note that the thumb 25 // Margin from edge of thumb to closest edge of view. Note that the thumb
26 // margins must be sufficiently large to allow space for the shadow. 26 // margins must be sufficiently large to allow space for the shadow.
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?
32 const SkColor kTrackOffColor =
33 SkColorSetA(SK_ColorBLACK, gfx::kDisabledControlAlpha);
34
35 } // namespace 31 } // namespace
36 32
37 // Class representing the thumb. When the thumb is clicked it is separated into 33 // Class representing the thumb (the circle that slides horizontally).
38 // its own layer and the ink drop layer is made a child of the thumb layer 34 class ToggleButton::ThumbView : public InkDropHostView {
39 // allowing the two to animate in sync.
40 class ToggleButton::ThumbView : public views::View {
41 public: 35 public:
42 ThumbView() : color_ratio_(0.) {} 36 ThumbView() : color_ratio_(0.) {}
43 ~ThumbView() override {} 37 ~ThumbView() override {}
44 38
45 void AddInkDropLayer(ui::Layer* ink_drop_layer) {
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) { 39 void Update(const gfx::Rect& bounds, double color_ratio) {
57 SetBoundsRect(bounds); 40 SetBoundsRect(bounds);
58 color_ratio_ = color_ratio; 41 color_ratio_ = color_ratio;
59 SchedulePaint(); 42 SchedulePaint();
60 } 43 }
61 44
45 // Returns the extra space needed to draw the shadows around the thumb. Since
46 // the extra space is around the thumb, the insets will be negative.
47 static gfx::Insets GetShadowOutsets() {
48 return gfx::Insets(-kShadowBlur)
49 .Offset(gfx::Vector2d(kShadowOffsetX, kShadowOffsetY));
50 }
51
62 private: 52 private:
53 static const int kShadowOffsetX = 0;
54 static const int kShadowOffsetY = 1;
55 static const int kShadowBlur = 2;
56
63 // views::View: 57 // views::View:
64 const char* GetClassName() const override { 58 const char* GetClassName() const override {
65 return "ToggleButton::ThumbView"; 59 return "ToggleButton::ThumbView";
66 } 60 }
67 61
68 void OnPaint(gfx::Canvas* canvas) override { 62 void OnPaint(gfx::Canvas* canvas) override {
63 const float dsf = canvas->UndoDeviceScaleFactor();
69 std::vector<gfx::ShadowValue> shadows; 64 std::vector<gfx::ShadowValue> shadows;
70 shadows.emplace_back(gfx::Vector2d(0, 1), 4.f, 65 gfx::ShadowValue shadow(
71 SkColorSetA(SK_ColorBLACK, 0x99)); 66 gfx::Vector2d(kShadowOffsetX, kShadowOffsetY), 2 * kShadowBlur,
67 SkColorSetA(GetNativeTheme()->GetSystemColor(
68 ui::NativeTheme::kColorId_LabelEnabledColor),
69 0x99));
70 shadows.push_back(shadow.Scale(dsf));
72 SkPaint thumb_paint; 71 SkPaint thumb_paint;
73 thumb_paint.setLooper(gfx::CreateShadowDrawLooperCorrectBlur(shadows)); 72 thumb_paint.setLooper(gfx::CreateShadowDrawLooperCorrectBlur(shadows));
74 thumb_paint.setStyle(SkPaint::kFill_Style);
75 thumb_paint.setAntiAlias(true); 73 thumb_paint.setAntiAlias(true);
76 const SkColor thumb_on_color = GetNativeTheme()->GetSystemColor( 74 const SkColor thumb_on_color = GetNativeTheme()->GetSystemColor(
77 ui::NativeTheme::kColorId_ProminentButtonColor); 75 ui::NativeTheme::kColorId_ProminentButtonColor);
78 // TODO(estade): get this color from the theme? 76 const SkColor thumb_off_color = GetNativeTheme()->GetSystemColor(
79 const SkColor thumb_off_color = SK_ColorWHITE; 77 ui::NativeTheme::kColorId_DialogBackground);
80 const SkAlpha blend = static_cast<SkAlpha>(SK_AlphaOPAQUE * color_ratio_); 78 const SkAlpha blend = static_cast<SkAlpha>(SK_AlphaOPAQUE * color_ratio_);
81 thumb_paint.setColor( 79 thumb_paint.setColor(
82 color_utils::AlphaBlend(thumb_on_color, thumb_off_color, blend)); 80 color_utils::AlphaBlend(thumb_on_color, thumb_off_color, blend));
83 gfx::Rect thumb_bounds = GetLocalBounds(); 81
84 thumb_bounds.Inset(gfx::Insets(kThumbVerticalMargin)); 82 // We want the circle to have an integer pixel diameter and to be aligned
85 canvas->DrawCircle(gfx::RectF(thumb_bounds).CenterPoint(), 83 // with pixel boundaries, so we scale dip bounds to pixel bounds and round.
86 thumb_bounds.height() / 2.f, thumb_paint); 84 gfx::RectF thumb_bounds(GetLocalBounds());
85 thumb_bounds.Inset(-GetShadowOutsets());
86 thumb_bounds.Inset(gfx::InsetsF(0.5f));
87 thumb_bounds.Scale(dsf);
88 thumb_bounds = gfx::RectF(gfx::ToEnclosingRect(thumb_bounds));
89 canvas->DrawCircle(thumb_bounds.CenterPoint(), thumb_bounds.height() / 2.f,
90 thumb_paint);
87 } 91 }
88 92
89 // Color ratio between 0 and 1 that controls the thumb color. 93 // Color ratio between 0 and 1 that controls the thumb color.
90 double color_ratio_; 94 double color_ratio_;
91 95
92 DISALLOW_COPY_AND_ASSIGN(ThumbView); 96 DISALLOW_COPY_AND_ASSIGN(ThumbView);
93 }; 97 };
94 98
95 // static 99 // static
96 const char ToggleButton::kViewClassName[] = "ToggleButton"; 100 const char ToggleButton::kViewClassName[] = "ToggleButton";
97 101
98 ToggleButton::ToggleButton(ButtonListener* listener) 102 ToggleButton::ToggleButton(ButtonListener* listener)
99 : CustomButton(listener), 103 : CustomButton(listener),
100 is_on_(false), 104 is_on_(false),
101 slide_animation_(this), 105 slide_animation_(this),
102 thumb_view_(new ToggleButton::ThumbView()) { 106 thumb_view_(new ThumbView()) {
103 slide_animation_.SetSlideDuration(80 /* ms */); 107 slide_animation_.SetSlideDuration(80 /* ms */);
104 slide_animation_.SetTweenType(gfx::Tween::LINEAR); 108 slide_animation_.SetTweenType(gfx::Tween::LINEAR);
105 SetBorder(Border::CreateEmptyBorder( 109 SetBorder(Border::CreateEmptyBorder(
106 gfx::Insets(kTrackVerticalMargin, kTrackHorizontalMargin))); 110 gfx::Insets(kTrackVerticalMargin, kTrackHorizontalMargin)));
107 AddChildView(thumb_view_.get()); 111 AddChildView(thumb_view_);
108 SetInkDropMode(InkDropMode::ON); 112 SetInkDropMode(InkDropMode::ON);
109 set_has_ink_drop_action_on_click(true); 113 set_has_ink_drop_action_on_click(true);
110 } 114 }
111 115
112 ToggleButton::~ToggleButton() { 116 ToggleButton::~ToggleButton() {
113 // Destroying ink drop early allows ink drop layer to be properly removed, 117 // Destroying ink drop early allows ink drop layer to be properly removed,
114 SetInkDropMode(InkDropMode::OFF); 118 SetInkDropMode(InkDropMode::OFF);
115 } 119 }
116 120
117 void ToggleButton::SetIsOn(bool is_on, bool animate) { 121 void ToggleButton::SetIsOn(bool is_on, bool animate) {
(...skipping 14 matching lines...) Expand all
132 136
133 gfx::Rect ToggleButton::GetThumbBounds() const { 137 gfx::Rect ToggleButton::GetThumbBounds() const {
134 gfx::Rect thumb_bounds = GetLocalBounds(); 138 gfx::Rect thumb_bounds = GetLocalBounds();
135 thumb_bounds.Inset(gfx::Insets(kThumbVerticalMargin, kThumbHorizontalMargin)); 139 thumb_bounds.Inset(gfx::Insets(kThumbVerticalMargin, kThumbHorizontalMargin));
136 thumb_bounds.set_x(thumb_bounds.x() + 140 thumb_bounds.set_x(thumb_bounds.x() +
137 slide_animation_.GetCurrentValue() * 141 slide_animation_.GetCurrentValue() *
138 (thumb_bounds.width() - thumb_bounds.height())); 142 (thumb_bounds.width() - thumb_bounds.height()));
139 // The thumb is a circle, so the width should match the height. 143 // The thumb is a circle, so the width should match the height.
140 thumb_bounds.set_width(thumb_bounds.height()); 144 thumb_bounds.set_width(thumb_bounds.height());
141 thumb_bounds.set_x(GetMirroredXForRect(thumb_bounds)); 145 thumb_bounds.set_x(GetMirroredXForRect(thumb_bounds));
146 thumb_bounds.Inset(ThumbView::GetShadowOutsets());
142 return thumb_bounds; 147 return thumb_bounds;
143 } 148 }
144 149
145 void ToggleButton::UpdateThumb() { 150 void ToggleButton::UpdateThumb() {
146 gfx::Rect thumb_bounds = GetThumbBounds(); 151 thumb_view_->Update(GetThumbBounds(), slide_animation_.GetCurrentValue());
147 thumb_bounds.Inset(gfx::Insets(-kThumbVerticalMargin)); 152 }
148 thumb_view_->Update(thumb_bounds, slide_animation_.GetCurrentValue()); 153
154 SkColor ToggleButton::GetTrackColor(bool is_on) const {
155 const SkAlpha kOffTrackAlpha = 0x29;
156 const SkAlpha kOnTrackAlpha = kOffTrackAlpha * 2;
157 ui::NativeTheme::ColorId color_id =
158 is_on ? ui::NativeTheme::kColorId_ProminentButtonColor
159 : ui::NativeTheme::kColorId_LabelEnabledColor;
160 return SkColorSetA(GetNativeTheme()->GetSystemColor(color_id),
161 is_on ? kOnTrackAlpha : kOffTrackAlpha);
149 } 162 }
150 163
151 gfx::Size ToggleButton::GetPreferredSize() const { 164 gfx::Size ToggleButton::GetPreferredSize() const {
152 gfx::Rect rect(0, 0, kTrackWidth, kTrackHeight); 165 gfx::Rect rect(0, 0, kTrackWidth, kTrackHeight);
153 if (border()) 166 if (border())
154 rect.Inset(-border()->GetInsets()); 167 rect.Inset(-border()->GetInsets());
155 return rect.size(); 168 return rect.size();
156 } 169 }
157 170
158 const char* ToggleButton::GetClassName() const { 171 const char* ToggleButton::GetClassName() const {
159 return kViewClassName; 172 return kViewClassName;
160 } 173 }
161 174
162 void ToggleButton::OnPaint(gfx::Canvas* canvas) { 175 void ToggleButton::OnPaint(gfx::Canvas* canvas) {
163 // Paint the toggle track. 176 // Paint the toggle track. To look sharp even at fractional scale factors,
177 // round up to pixel boundaries.
Evan Stade 2016/11/01 16:26:23 added this improvement as well (visible with dsf=1
178 float dsf = canvas->UndoDeviceScaleFactor();
164 gfx::RectF track_rect(GetContentsBounds()); 179 gfx::RectF track_rect(GetContentsBounds());
180 track_rect.Scale(dsf);
181 track_rect = gfx::RectF(gfx::ToEnclosingRect(track_rect));
165 SkPaint track_paint; 182 SkPaint track_paint;
166 track_paint.setAntiAlias(true); 183 track_paint.setAntiAlias(true);
167 const SkColor track_on_color =
168 SkColorSetA(GetNativeTheme()->GetSystemColor(
169 ui::NativeTheme::kColorId_ProminentButtonColor),
170 0xFF / 2);
171 const double color_ratio = slide_animation_.GetCurrentValue(); 184 const double color_ratio = slide_animation_.GetCurrentValue();
172 track_paint.setColor(color_utils::AlphaBlend( 185 track_paint.setColor(color_utils::AlphaBlend(
173 track_on_color, kTrackOffColor, 186 GetTrackColor(true), GetTrackColor(false),
174 static_cast<SkAlpha>(SK_AlphaOPAQUE * color_ratio))); 187 static_cast<SkAlpha>(SK_AlphaOPAQUE * color_ratio)));
175 canvas->DrawRoundRect(track_rect, track_rect.height() / 2, track_paint); 188 canvas->DrawRoundRect(track_rect, track_rect.height() / 2, track_paint);
176 } 189 }
177 190
178 void ToggleButton::NotifyClick(const ui::Event& event) { 191 void ToggleButton::NotifyClick(const ui::Event& event) {
179 SetIsOn(!is_on(), true); 192 SetIsOn(!is_on(), true);
180 CustomButton::NotifyClick(event); 193 CustomButton::NotifyClick(event);
181 } 194 }
182 195
183 void ToggleButton::OnBoundsChanged(const gfx::Rect& previous_bounds) { 196 void ToggleButton::OnBoundsChanged(const gfx::Rect& previous_bounds) {
184 UpdateThumb(); 197 UpdateThumb();
185 } 198 }
186 199
187 void ToggleButton::OnNativeThemeChanged(const ui::NativeTheme* theme) { 200 void ToggleButton::OnNativeThemeChanged(const ui::NativeTheme* theme) {
188 SchedulePaint(); 201 SchedulePaint();
189 } 202 }
190 203
191 void ToggleButton::AddInkDropLayer(ui::Layer* ink_drop_layer) { 204 void ToggleButton::AddInkDropLayer(ui::Layer* ink_drop_layer) {
192 thumb_view_->AddInkDropLayer(ink_drop_layer); 205 thumb_view_->AddInkDropLayer(ink_drop_layer);
193 UpdateThumb();
194 SchedulePaint();
195 } 206 }
196 207
197 void ToggleButton::RemoveInkDropLayer(ui::Layer* ink_drop_layer) { 208 void ToggleButton::RemoveInkDropLayer(ui::Layer* ink_drop_layer) {
198 thumb_view_->RemoveInkDropLayer(ink_drop_layer); 209 thumb_view_->RemoveInkDropLayer(ink_drop_layer);
199 SchedulePaint();
200 } 210 }
201 211
202 std::unique_ptr<InkDropRipple> ToggleButton::CreateInkDropRipple() const { 212 std::unique_ptr<InkDropRipple> ToggleButton::CreateInkDropRipple() const {
203 const int radius = (kTrackHeight + kTrackVerticalMargin * 2) / 2; 213 gfx::Rect rect = thumb_view_->GetLocalBounds();
204 return CreateDefaultInkDropRipple(gfx::Point(radius, radius)); 214 rect.Inset(-ThumbView::GetShadowOutsets());
215 return CreateDefaultInkDropRipple(rect.CenterPoint());
205 } 216 }
206 217
207 SkColor ToggleButton::GetInkDropBaseColor() const { 218 SkColor ToggleButton::GetInkDropBaseColor() const {
208 return is_on() 219 return GetTrackColor(is_on());
209 ? GetNativeTheme()->GetSystemColor(
210 ui::NativeTheme::kColorId_ProminentButtonColor)
211 : kTrackOffColor;
212 } 220 }
213 221
214 bool ToggleButton::ShouldShowInkDropHighlight() const { 222 bool ToggleButton::ShouldShowInkDropHighlight() const {
215 return false; 223 return false;
216 } 224 }
217 225
218 void ToggleButton::AnimationProgressed(const gfx::Animation* animation) { 226 void ToggleButton::AnimationProgressed(const gfx::Animation* animation) {
219 if (animation == &slide_animation_) { 227 if (animation == &slide_animation_) {
220 // TODO(varkha, estade): The thumb is using its own view. Investigate if 228 // TODO(varkha, estade): The thumb is using its own view. Investigate if
221 // repainting in every animation step to update colors could be avoided. 229 // repainting in every animation step to update colors could be avoided.
222 UpdateThumb(); 230 UpdateThumb();
223 SchedulePaint(); 231 SchedulePaint();
224 return; 232 return;
225 } 233 }
226 CustomButton::AnimationProgressed(animation); 234 CustomButton::AnimationProgressed(animation);
227 } 235 }
228 236
229 } // namespace views 237 } // namespace views
OLDNEW
« no previous file with comments | « ui/views/controls/button/toggle_button.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698