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

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

Issue 2506133003: [ash-md] Allows ToggleButton to have a border and adds focus rectangle (Closed)
Patch Set: [ash-md] Allows ToggleButton to have a border and adds focus rectangle (nits) 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/accessibility/ax_node_data.h" 9 #include "ui/accessibility/ax_node_data.h"
10 #include "ui/gfx/canvas.h" 10 #include "ui/gfx/canvas.h"
11 #include "ui/gfx/color_palette.h" 11 #include "ui/gfx/color_palette.h"
12 #include "ui/gfx/color_utils.h" 12 #include "ui/gfx/color_utils.h"
13 #include "ui/gfx/geometry/rect_conversions.h"
13 #include "ui/views/animation/ink_drop_impl.h" 14 #include "ui/views/animation/ink_drop_impl.h"
14 #include "ui/views/animation/ink_drop_ripple.h" 15 #include "ui/views/animation/ink_drop_ripple.h"
15 #include "ui/views/border.h" 16 #include "ui/views/border.h"
17 #include "ui/views/painter.h"
16 18
17 namespace views { 19 namespace views {
18 20
19 namespace { 21 namespace {
20 22
21 // Constants are measured in dip. 23 // Constants are measured in dip.
22 const int kTrackHeight = 12; 24 const int kTrackHeight = 12;
23 const int kTrackWidth = 28; 25 const int kTrackWidth = 28;
24 // Margins from edge of track to edge of view. 26 // Margins from edge of track to edge of view.
25 const int kTrackVerticalMargin = 5; 27 const int kTrackVerticalMargin = 5;
26 const int kTrackHorizontalMargin = 6; 28 const int kTrackHorizontalMargin = 6;
27 // Margin from edge of thumb to closest edge of view. Note that the thumb 29 // Inset from the rounded edge of the thumb to the rounded edge of the track.
28 // margins must be sufficiently large to allow space for the shadow. 30 const int kThumbInset = 2;
29 const int kThumbHorizontalMargin = 4;
30 // Margin from top/bottom edge of thumb to top/bottom edge of view.
31 const int kThumbVerticalMargin = 3;
32 31
33 } // namespace 32 } // namespace
34 33
35 // Class representing the thumb (the circle that slides horizontally). 34 // Class representing the thumb (the circle that slides horizontally).
36 class ToggleButton::ThumbView : public InkDropHostView { 35 class ToggleButton::ThumbView : public InkDropHostView {
37 public: 36 public:
38 ThumbView() : color_ratio_(0.) {} 37 ThumbView() : color_ratio_(0.) {}
39 ~ThumbView() override {} 38 ~ThumbView() override {}
40 39
41 void Update(const gfx::Rect& bounds, double color_ratio) { 40 void Update(const gfx::Rect& bounds, double color_ratio) {
42 SetBoundsRect(bounds); 41 SetBoundsRect(bounds);
43 color_ratio_ = color_ratio; 42 color_ratio_ = color_ratio;
44 SchedulePaint(); 43 SchedulePaint();
45 } 44 }
46 45
47 // Returns the extra space needed to draw the shadows around the thumb. Since 46 // Returns the extra space needed to draw the shadows around the thumb. Since
48 // the extra space is around the thumb, the insets will be negative. 47 // the extra space is around the thumb, the insets will be negative.
49 static gfx::Insets GetShadowOutsets() { 48 static gfx::Insets GetShadowOutsets() {
50 return gfx::Insets(-kShadowBlur) 49 return gfx::Insets(-kShadowBlur)
51 .Offset(gfx::Vector2d(kShadowOffsetX, kShadowOffsetY)); 50 .Offset(gfx::Vector2d(kShadowOffsetX, kShadowOffsetY));
52 } 51 }
53 52
53 protected:
54 // views::View:
55 bool CanProcessEventsWithinSubtree() const override {
56 // Make the thumb behave as part of the parent for event handling.
Evan Stade 2016/11/18 14:29:06 other events like clicks and so forth already tric
Evan Stade 2016/11/18 16:25:38 I guess it's good to keep this anyway as some othe
57 return false;
58 }
59
54 private: 60 private:
55 static const int kShadowOffsetX = 0; 61 static const int kShadowOffsetX = 0;
56 static const int kShadowOffsetY = 1; 62 static const int kShadowOffsetY = 1;
57 static const int kShadowBlur = 2; 63 static const int kShadowBlur = 2;
58 64
59 // views::View: 65 // views::View:
60 const char* GetClassName() const override { 66 const char* GetClassName() const override {
61 return "ToggleButton::ThumbView"; 67 return "ToggleButton::ThumbView";
62 } 68 }
63 69
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
101 // static 107 // static
102 const char ToggleButton::kViewClassName[] = "ToggleButton"; 108 const char ToggleButton::kViewClassName[] = "ToggleButton";
103 109
104 ToggleButton::ToggleButton(ButtonListener* listener) 110 ToggleButton::ToggleButton(ButtonListener* listener)
105 : CustomButton(listener), 111 : CustomButton(listener),
106 is_on_(false), 112 is_on_(false),
107 slide_animation_(this), 113 slide_animation_(this),
108 thumb_view_(new ThumbView()) { 114 thumb_view_(new ThumbView()) {
109 slide_animation_.SetSlideDuration(80 /* ms */); 115 slide_animation_.SetSlideDuration(80 /* ms */);
110 slide_animation_.SetTweenType(gfx::Tween::LINEAR); 116 slide_animation_.SetTweenType(gfx::Tween::LINEAR);
111 SetBorder(CreateEmptyBorder(
112 gfx::Insets(kTrackVerticalMargin, kTrackHorizontalMargin)));
113 AddChildView(thumb_view_); 117 AddChildView(thumb_view_);
114 SetInkDropMode(InkDropMode::ON); 118 SetInkDropMode(InkDropMode::ON);
119 SetFocusForPlatform();
115 set_has_ink_drop_action_on_click(true); 120 set_has_ink_drop_action_on_click(true);
116 } 121 }
117 122
118 ToggleButton::~ToggleButton() { 123 ToggleButton::~ToggleButton() {
119 // Destroying ink drop early allows ink drop layer to be properly removed, 124 // Destroying ink drop early allows ink drop layer to be properly removed,
120 SetInkDropMode(InkDropMode::OFF); 125 SetInkDropMode(InkDropMode::OFF);
121 } 126 }
122 127
123 void ToggleButton::SetIsOn(bool is_on, bool animate) { 128 void ToggleButton::SetIsOn(bool is_on, bool animate) {
124 if (is_on_ == is_on) 129 if (is_on_ == is_on)
125 return; 130 return;
126 131
127 is_on_ = is_on; 132 is_on_ = is_on;
128 if (!animate) { 133 if (!animate) {
129 slide_animation_.Reset(is_on_ ? 1.0 : 0.0); 134 slide_animation_.Reset(is_on_ ? 1.0 : 0.0);
130 UpdateThumb(); 135 UpdateThumb();
131 SchedulePaint(); 136 SchedulePaint();
132 } else if (is_on_) { 137 } else if (is_on_) {
133 slide_animation_.Show(); 138 slide_animation_.Show();
134 } else { 139 } else {
135 slide_animation_.Hide(); 140 slide_animation_.Hide();
136 } 141 }
137 } 142 }
138 143
144 void ToggleButton::set_focus_painter(std::unique_ptr<Painter> focus_painter) {
sadrul 2016/11/18 16:37:30 Not sure if std::move is trivial enough to allow t
varkha 2016/11/18 16:55:35 Done.
Evan Stade 2016/11/18 17:10:42 I requested set_focus_painter --- it seems that st
sadrul 2016/11/18 17:22:45 set_background takes a raw-pointer, vs. SetBorder
145 focus_painter_ = std::move(focus_painter);
146 }
147
148 gfx::Size ToggleButton::GetPreferredSize() const {
149 gfx::Rect rect(kTrackWidth, kTrackHeight);
150 rect.Inset(gfx::Insets(-kTrackVerticalMargin, -kTrackHorizontalMargin));
151 if (border())
152 rect.Inset(-border()->GetInsets());
153 return rect.size();
154 }
155
156 gfx::Rect ToggleButton::GetTrackBounds() const {
157 gfx::Rect track_bounds(GetContentsBounds());
158 track_bounds.ClampToCenteredSize(gfx::Size(kTrackWidth, kTrackHeight));
159 return track_bounds;
160 }
161
139 gfx::Rect ToggleButton::GetThumbBounds() const { 162 gfx::Rect ToggleButton::GetThumbBounds() const {
140 gfx::Rect thumb_bounds = GetLocalBounds(); 163 gfx::Rect thumb_bounds(GetTrackBounds());
141 thumb_bounds.Inset(gfx::Insets(kThumbVerticalMargin, kThumbHorizontalMargin)); 164 thumb_bounds.Inset(gfx::Insets(-kThumbInset));
142 thumb_bounds.set_x(thumb_bounds.x() + 165 thumb_bounds.set_x(thumb_bounds.x() +
143 slide_animation_.GetCurrentValue() * 166 slide_animation_.GetCurrentValue() *
144 (thumb_bounds.width() - thumb_bounds.height())); 167 (thumb_bounds.width() - thumb_bounds.height()));
145 // The thumb is a circle, so the width should match the height. 168 // The thumb is a circle, so the width should match the height.
146 thumb_bounds.set_width(thumb_bounds.height()); 169 thumb_bounds.set_width(thumb_bounds.height());
147 thumb_bounds.set_x(GetMirroredXForRect(thumb_bounds)); 170 thumb_bounds.set_x(GetMirroredXForRect(thumb_bounds));
148 thumb_bounds.Inset(ThumbView::GetShadowOutsets()); 171 thumb_bounds.Inset(ThumbView::GetShadowOutsets());
149 return thumb_bounds; 172 return thumb_bounds;
150 } 173 }
151 174
152 void ToggleButton::UpdateThumb() { 175 void ToggleButton::UpdateThumb() {
153 thumb_view_->Update(GetThumbBounds(), slide_animation_.GetCurrentValue()); 176 thumb_view_->Update(GetThumbBounds(), slide_animation_.GetCurrentValue());
154 } 177 }
155 178
156 SkColor ToggleButton::GetTrackColor(bool is_on) const { 179 SkColor ToggleButton::GetTrackColor(bool is_on) const {
157 const SkAlpha kOffTrackAlpha = 0x29; 180 const SkAlpha kOffTrackAlpha = 0x29;
158 const SkAlpha kOnTrackAlpha = kOffTrackAlpha * 2; 181 const SkAlpha kOnTrackAlpha = kOffTrackAlpha * 2;
159 ui::NativeTheme::ColorId color_id = 182 ui::NativeTheme::ColorId color_id =
160 is_on ? ui::NativeTheme::kColorId_ProminentButtonColor 183 is_on ? ui::NativeTheme::kColorId_ProminentButtonColor
161 : ui::NativeTheme::kColorId_LabelEnabledColor; 184 : ui::NativeTheme::kColorId_LabelEnabledColor;
162 return SkColorSetA(GetNativeTheme()->GetSystemColor(color_id), 185 return SkColorSetA(GetNativeTheme()->GetSystemColor(color_id),
163 is_on ? kOnTrackAlpha : kOffTrackAlpha); 186 is_on ? kOnTrackAlpha : kOffTrackAlpha);
164 } 187 }
165 188
166 gfx::Size ToggleButton::GetPreferredSize() const {
167 gfx::Rect rect(0, 0, kTrackWidth, kTrackHeight);
168 if (border())
169 rect.Inset(-border()->GetInsets());
170 return rect.size();
171 }
172
173 const char* ToggleButton::GetClassName() const { 189 const char* ToggleButton::GetClassName() const {
174 return kViewClassName; 190 return kViewClassName;
175 } 191 }
176 192
177 void ToggleButton::OnPaint(gfx::Canvas* canvas) { 193 void ToggleButton::OnPaint(gfx::Canvas* canvas) {
178 // Paint the toggle track. To look sharp even at fractional scale factors, 194 // Paint the toggle track. To look sharp even at fractional scale factors,
179 // round up to pixel boundaries. 195 // round up to pixel boundaries.
196 canvas->Save();
sadrul 2016/11/18 16:37:30 gfx::ScopedCanvas But why do you need to do this?
varkha 2016/11/18 16:55:35 This is to restore scale before painting the focus
180 float dsf = canvas->UndoDeviceScaleFactor(); 197 float dsf = canvas->UndoDeviceScaleFactor();
181 gfx::RectF track_rect(GetContentsBounds()); 198 gfx::RectF track_rect(GetTrackBounds());
182 track_rect.Scale(dsf); 199 track_rect.Scale(dsf);
183 track_rect = gfx::RectF(gfx::ToEnclosingRect(track_rect)); 200 track_rect = gfx::RectF(gfx::ToEnclosingRect(track_rect));
184 SkPaint track_paint; 201 SkPaint track_paint;
185 track_paint.setAntiAlias(true); 202 track_paint.setAntiAlias(true);
186 const double color_ratio = slide_animation_.GetCurrentValue(); 203 const double color_ratio = slide_animation_.GetCurrentValue();
187 track_paint.setColor(color_utils::AlphaBlend( 204 track_paint.setColor(color_utils::AlphaBlend(
188 GetTrackColor(true), GetTrackColor(false), 205 GetTrackColor(true), GetTrackColor(false),
189 static_cast<SkAlpha>(SK_AlphaOPAQUE * color_ratio))); 206 static_cast<SkAlpha>(SK_AlphaOPAQUE * color_ratio)));
190 canvas->DrawRoundRect(track_rect, track_rect.height() / 2, track_paint); 207 canvas->DrawRoundRect(track_rect, track_rect.height() / 2, track_paint);
208 canvas->Restore();
209
210 views::Painter::PaintFocusPainter(this, canvas, focus_painter_.get());
sadrul 2016/11/18 16:37:30 Omit views::
varkha 2016/11/18 16:55:35 Done.
191 } 211 }
192 212
193 void ToggleButton::NotifyClick(const ui::Event& event) { 213 void ToggleButton::OnFocus() {
194 SetIsOn(!is_on(), true); 214 CustomButton::OnFocus();
195 CustomButton::NotifyClick(event); 215 if (focus_painter_)
216 SchedulePaint();
217 }
218
219 void ToggleButton::OnBlur() {
220 CustomButton::OnBlur();
221 if (focus_painter_)
222 SchedulePaint();
196 } 223 }
197 224
198 void ToggleButton::OnBoundsChanged(const gfx::Rect& previous_bounds) { 225 void ToggleButton::OnBoundsChanged(const gfx::Rect& previous_bounds) {
199 UpdateThumb(); 226 UpdateThumb();
200 } 227 }
201 228
202 void ToggleButton::OnNativeThemeChanged(const ui::NativeTheme* theme) { 229 void ToggleButton::OnNativeThemeChanged(const ui::NativeTheme* theme) {
203 SchedulePaint(); 230 SchedulePaint();
204 } 231 }
205 232
206 void ToggleButton::GetAccessibleNodeData(ui::AXNodeData* node_data) { 233 void ToggleButton::GetAccessibleNodeData(ui::AXNodeData* node_data) {
207 CustomButton::GetAccessibleNodeData(node_data); 234 CustomButton::GetAccessibleNodeData(node_data);
208 235
209 node_data->role = ui::AX_ROLE_SWITCH; 236 node_data->role = ui::AX_ROLE_SWITCH;
210 if (is_on_) 237 if (is_on_)
211 node_data->AddStateFlag(ui::AX_STATE_CHECKED); 238 node_data->AddStateFlag(ui::AX_STATE_CHECKED);
212 } 239 }
213 240
241 void ToggleButton::NotifyClick(const ui::Event& event) {
242 SetIsOn(!is_on(), true);
243 CustomButton::NotifyClick(event);
244 }
245
214 void ToggleButton::AddInkDropLayer(ui::Layer* ink_drop_layer) { 246 void ToggleButton::AddInkDropLayer(ui::Layer* ink_drop_layer) {
215 thumb_view_->AddInkDropLayer(ink_drop_layer); 247 thumb_view_->AddInkDropLayer(ink_drop_layer);
216 } 248 }
217 249
218 void ToggleButton::RemoveInkDropLayer(ui::Layer* ink_drop_layer) { 250 void ToggleButton::RemoveInkDropLayer(ui::Layer* ink_drop_layer) {
219 thumb_view_->RemoveInkDropLayer(ink_drop_layer); 251 thumb_view_->RemoveInkDropLayer(ink_drop_layer);
220 } 252 }
221 253
222 std::unique_ptr<InkDrop> ToggleButton::CreateInkDrop() { 254 std::unique_ptr<InkDrop> ToggleButton::CreateInkDrop() {
223 std::unique_ptr<InkDropImpl> ink_drop = 255 std::unique_ptr<InkDropImpl> ink_drop =
(...skipping 17 matching lines...) Expand all
241 // TODO(varkha, estade): The thumb is using its own view. Investigate if 273 // TODO(varkha, estade): The thumb is using its own view. Investigate if
242 // repainting in every animation step to update colors could be avoided. 274 // repainting in every animation step to update colors could be avoided.
243 UpdateThumb(); 275 UpdateThumb();
244 SchedulePaint(); 276 SchedulePaint();
245 return; 277 return;
246 } 278 }
247 CustomButton::AnimationProgressed(animation); 279 CustomButton::AnimationProgressed(animation);
248 } 280 }
249 281
250 } // namespace views 282 } // 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